selectools 1.1.0__tar.gz → 1.2.0__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 (323) hide show
  1. {selectools-1.1.0/src/selectools.egg-info → selectools-1.2.0}/PKG-INFO +1 -1
  2. {selectools-1.1.0 → selectools-1.2.0}/pyproject.toml +1 -1
  3. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/__init__.py +1 -1
  4. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/_tool_executor.py +44 -6
  5. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/config_groups.py +35 -3
  6. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/core.py +446 -46
  7. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/audit.py +19 -0
  8. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/base.py +32 -6
  9. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/pipeline.py +76 -6
  10. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/observer.py +33 -0
  11. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/_starlette_app.py +7 -1
  12. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/_static/builder.js +1 -1
  13. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/app.py +41 -5
  14. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/types.py +13 -0
  15. {selectools-1.1.0 → selectools-1.2.0/src/selectools.egg-info}/PKG-INFO +1 -1
  16. {selectools-1.1.0 → selectools-1.2.0}/tests/test_guardrails.py +59 -0
  17. {selectools-1.1.0 → selectools-1.2.0}/tests/test_serve_app_coverage.py +10 -0
  18. {selectools-1.1.0 → selectools-1.2.0}/tests/test_visual_builder.py +48 -9
  19. {selectools-1.1.0 → selectools-1.2.0}/LICENSE +0 -0
  20. {selectools-1.1.0 → selectools-1.2.0}/README.md +0 -0
  21. {selectools-1.1.0 → selectools-1.2.0}/setup.cfg +0 -0
  22. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/_async_utils.py +0 -0
  23. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/_json_utils.py +0 -0
  24. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/_ssrf.py +0 -0
  25. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/_time.py +0 -0
  26. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/a2a/__init__.py +0 -0
  27. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/a2a/client.py +0 -0
  28. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/a2a/server.py +0 -0
  29. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/a2a/types.py +0 -0
  30. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/__init__.py +0 -0
  31. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/_lifecycle.py +0 -0
  32. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/_memory_manager.py +0 -0
  33. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/_planning.py +0 -0
  34. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/_provider_caller.py +0 -0
  35. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/agent/config.py +0 -0
  36. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/analytics.py +0 -0
  37. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/cache.py +0 -0
  38. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/cache_redis.py +0 -0
  39. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/cache_semantic.py +0 -0
  40. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/cancellation.py +0 -0
  41. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/checkpoint_postgres.py +0 -0
  42. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/coherence.py +0 -0
  43. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/compose.py +0 -0
  44. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/__init__.py +0 -0
  45. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/anthropic.py +0 -0
  46. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/cohere.py +0 -0
  47. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/gemini.py +0 -0
  48. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/openai.py +0 -0
  49. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/embeddings/provider.py +0 -0
  50. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/entity_memory.py +0 -0
  51. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/env.py +0 -0
  52. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/__init__.py +0 -0
  53. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/__main__.py +0 -0
  54. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/badge.py +0 -0
  55. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/dataset.py +0 -0
  56. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/evaluators.py +0 -0
  57. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/generator.py +0 -0
  58. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/history.py +0 -0
  59. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/html.py +0 -0
  60. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/junit.py +0 -0
  61. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/llm_evaluators.py +0 -0
  62. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/pairwise.py +0 -0
  63. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/regression.py +0 -0
  64. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/report.py +0 -0
  65. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/serve.py +0 -0
  66. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/snapshot.py +0 -0
  67. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/suite.py +0 -0
  68. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/templates.py +0 -0
  69. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/evals/types.py +0 -0
  70. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/exceptions.py +0 -0
  71. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/__init__.py +0 -0
  72. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/format.py +0 -0
  73. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/injection.py +0 -0
  74. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/length.py +0 -0
  75. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/pii.py +0 -0
  76. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/topic.py +0 -0
  77. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/guardrails/toxicity.py +0 -0
  78. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge.py +0 -0
  79. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge_backends.py +0 -0
  80. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge_graph.py +0 -0
  81. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge_sanitizers.py +0 -0
  82. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge_store_redis.py +0 -0
  83. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/knowledge_store_supabase.py +0 -0
  84. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/loop_detection.py +0 -0
  85. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/__init__.py +0 -0
  86. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/_loop.py +0 -0
  87. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/bridge.py +0 -0
  88. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/client.py +0 -0
  89. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/config.py +0 -0
  90. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/multi.py +0 -0
  91. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/mcp/server.py +0 -0
  92. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/memory.py +0 -0
  93. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/models.py +0 -0
  94. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/observe/__init__.py +0 -0
  95. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/observe/langfuse.py +0 -0
  96. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/observe/otel.py +0 -0
  97. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/observe/trace_store.py +0 -0
  98. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/__init__.py +0 -0
  99. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/checkpoint.py +0 -0
  100. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/graph.py +0 -0
  101. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/node.py +0 -0
  102. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/state.py +0 -0
  103. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/orchestration/supervisor.py +0 -0
  104. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/parser.py +0 -0
  105. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/patterns/__init__.py +0 -0
  106. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/patterns/debate.py +0 -0
  107. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/patterns/plan_and_execute.py +0 -0
  108. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/patterns/reflective.py +0 -0
  109. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/patterns/team_lead.py +0 -0
  110. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/pending.py +0 -0
  111. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/pipeline.py +0 -0
  112. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/policy.py +0 -0
  113. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/pricing.py +0 -0
  114. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/prompt.py +0 -0
  115. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/__init__.py +0 -0
  116. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/_openai_compat.py +0 -0
  117. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/anthropic_provider.py +0 -0
  118. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/azure_openai_provider.py +0 -0
  119. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/base.py +0 -0
  120. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/fallback.py +0 -0
  121. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/gemini_provider.py +0 -0
  122. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/litellm_provider.py +0 -0
  123. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/ollama_provider.py +0 -0
  124. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/openai_provider.py +0 -0
  125. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/router.py +0 -0
  126. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/providers/stubs.py +0 -0
  127. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/__init__.py +0 -0
  128. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/bm25.py +0 -0
  129. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/chunking.py +0 -0
  130. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/hybrid.py +0 -0
  131. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/loaders.py +0 -0
  132. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/reranker.py +0 -0
  133. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/__init__.py +0 -0
  134. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/chroma.py +0 -0
  135. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/faiss.py +0 -0
  136. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/memory.py +0 -0
  137. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/pgvector.py +0 -0
  138. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/pinecone.py +0 -0
  139. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/qdrant.py +0 -0
  140. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/stores/sqlite.py +0 -0
  141. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/tools.py +0 -0
  142. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/rag/vector_store.py +0 -0
  143. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/results.py +0 -0
  144. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/scheduler.py +0 -0
  145. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/security.py +0 -0
  146. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/__init__.py +0 -0
  147. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/_static/builder.css +0 -0
  148. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/_static/builder.html +0 -0
  149. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/api.py +0 -0
  150. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/builder.py +0 -0
  151. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/cli.py +0 -0
  152. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/models.py +0 -0
  153. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/serve/playground.py +0 -0
  154. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/sessions.py +0 -0
  155. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/stability.py +0 -0
  156. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/structured.py +0 -0
  157. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/__init__.py +0 -0
  158. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/code_reviewer.py +0 -0
  159. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/customer_support.py +0 -0
  160. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/data_analyst.py +0 -0
  161. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/rag_chatbot.py +0 -0
  162. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/templates/research_assistant.py +0 -0
  163. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/token_estimation.py +0 -0
  164. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/__init__.py +0 -0
  165. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/browser_tools.py +0 -0
  166. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/calculator_tools.py +0 -0
  167. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/code_tools.py +0 -0
  168. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/data_tools.py +0 -0
  169. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/datetime_tools.py +0 -0
  170. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/db_tools.py +0 -0
  171. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/discord_tools.py +0 -0
  172. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/email_tools.py +0 -0
  173. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/file_tools.py +0 -0
  174. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/github_tools.py +0 -0
  175. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/image_tools.py +0 -0
  176. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/linear_tools.py +0 -0
  177. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/memory_tools.py +0 -0
  178. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/notion_tools.py +0 -0
  179. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/pdf_tools.py +0 -0
  180. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/reasoning_tools.py +0 -0
  181. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/s3_tools.py +0 -0
  182. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/search_tools.py +0 -0
  183. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/slack_tools.py +0 -0
  184. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/text_tools.py +0 -0
  185. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/toolbox/web_tools.py +0 -0
  186. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/tools/__init__.py +0 -0
  187. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/tools/base.py +0 -0
  188. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/tools/decorators.py +0 -0
  189. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/tools/loader.py +0 -0
  190. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/tools/registry.py +0 -0
  191. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/trace.py +0 -0
  192. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/unified_memory.py +0 -0
  193. {selectools-1.1.0 → selectools-1.2.0}/src/selectools/usage.py +0 -0
  194. {selectools-1.1.0 → selectools-1.2.0}/src/selectools.egg-info/SOURCES.txt +0 -0
  195. {selectools-1.1.0 → selectools-1.2.0}/src/selectools.egg-info/dependency_links.txt +0 -0
  196. {selectools-1.1.0 → selectools-1.2.0}/src/selectools.egg-info/entry_points.txt +0 -0
  197. {selectools-1.1.0 → selectools-1.2.0}/src/selectools.egg-info/requires.txt +0 -0
  198. {selectools-1.1.0 → selectools-1.2.0}/src/selectools.egg-info/top_level.txt +0 -0
  199. {selectools-1.1.0 → selectools-1.2.0}/tests/test_a2a.py +0 -0
  200. {selectools-1.1.0 → selectools-1.2.0}/tests/test_agent_api.py +0 -0
  201. {selectools-1.1.0 → selectools-1.2.0}/tests/test_agent_hitl.py +0 -0
  202. {selectools-1.1.0 → selectools-1.2.0}/tests/test_approval_gate.py +0 -0
  203. {selectools-1.1.0 → selectools-1.2.0}/tests/test_architecture.py +0 -0
  204. {selectools-1.1.0 → selectools-1.2.0}/tests/test_async_observers.py +0 -0
  205. {selectools-1.1.0 → selectools-1.2.0}/tests/test_audit.py +0 -0
  206. {selectools-1.1.0 → selectools-1.2.0}/tests/test_bake_window_hunt.py +0 -0
  207. {selectools-1.1.0 → selectools-1.2.0}/tests/test_budget.py +0 -0
  208. {selectools-1.1.0 → selectools-1.2.0}/tests/test_bug_hunt_batch1_core.py +0 -0
  209. {selectools-1.1.0 → selectools-1.2.0}/tests/test_bug_hunt_batch1_security.py +0 -0
  210. {selectools-1.1.0 → selectools-1.2.0}/tests/test_bug_hunt_batch1_tools.py +0 -0
  211. {selectools-1.1.0 → selectools-1.2.0}/tests/test_bug_hunt_regression.py +0 -0
  212. {selectools-1.1.0 → selectools-1.2.0}/tests/test_cache.py +0 -0
  213. {selectools-1.1.0 → selectools-1.2.0}/tests/test_cache_redis.py +0 -0
  214. {selectools-1.1.0 → selectools-1.2.0}/tests/test_cancellation.py +0 -0
  215. {selectools-1.1.0 → selectools-1.2.0}/tests/test_checkpoint_postgres.py +0 -0
  216. {selectools-1.1.0 → selectools-1.2.0}/tests/test_coherence.py +0 -0
  217. {selectools-1.1.0 → selectools-1.2.0}/tests/test_concurrency_smoke.py +0 -0
  218. {selectools-1.1.0 → selectools-1.2.0}/tests/test_consolidation_regression.py +0 -0
  219. {selectools-1.1.0 → selectools-1.2.0}/tests/test_conversation_branching.py +0 -0
  220. {selectools-1.1.0 → selectools-1.2.0}/tests/test_coverage_orchestration.py +0 -0
  221. {selectools-1.1.0 → selectools-1.2.0}/tests/test_document_loaders_extended.py +0 -0
  222. {selectools-1.1.0 → selectools-1.2.0}/tests/test_e2e_langfuse_observer.py +0 -0
  223. {selectools-1.1.0 → selectools-1.2.0}/tests/test_e2e_multimodal.py +0 -0
  224. {selectools-1.1.0 → selectools-1.2.0}/tests/test_e2e_otel_observer.py +0 -0
  225. {selectools-1.1.0 → selectools-1.2.0}/tests/test_e2e_v0_21_0_apps.py +0 -0
  226. {selectools-1.1.0 → selectools-1.2.0}/tests/test_e2e_v0_21_0_simulations.py +0 -0
  227. {selectools-1.1.0 → selectools-1.2.0}/tests/test_entity_memory.py +0 -0
  228. {selectools-1.1.0 → selectools-1.2.0}/tests/test_env.py +0 -0
  229. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals.py +0 -0
  230. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_advanced.py +0 -0
  231. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_cli.py +0 -0
  232. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_e2e.py +0 -0
  233. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_final.py +0 -0
  234. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_hardening.py +0 -0
  235. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_html_report.py +0 -0
  236. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_new_evaluators.py +0 -0
  237. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_ralph_bugs.py +0 -0
  238. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_release.py +0 -0
  239. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_serve.py +0 -0
  240. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_v017_features.py +0 -0
  241. {selectools-1.1.0 → selectools-1.2.0}/tests/test_evals_v0191.py +0 -0
  242. {selectools-1.1.0 → selectools-1.2.0}/tests/test_features_in_graph.py +0 -0
  243. {selectools-1.1.0 → selectools-1.2.0}/tests/test_final_coverage_a.py +0 -0
  244. {selectools-1.1.0 → selectools-1.2.0}/tests/test_final_coverage_b.py +0 -0
  245. {selectools-1.1.0 → selectools-1.2.0}/tests/test_guardrails_injection.py +0 -0
  246. {selectools-1.1.0 → selectools-1.2.0}/tests/test_hardening.py +0 -0
  247. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge.py +0 -0
  248. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_backend.py +0 -0
  249. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_backend_redis.py +0 -0
  250. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_backend_supabase.py +0 -0
  251. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_graph.py +0 -0
  252. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_sanitizers.py +0 -0
  253. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_store_redis.py +0 -0
  254. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_store_supabase.py +0 -0
  255. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_stores.py +0 -0
  256. {selectools-1.1.0 → selectools-1.2.0}/tests/test_knowledge_stores_error_handling.py +0 -0
  257. {selectools-1.1.0 → selectools-1.2.0}/tests/test_langfuse_observer.py +0 -0
  258. {selectools-1.1.0 → selectools-1.2.0}/tests/test_loop_detection.py +0 -0
  259. {selectools-1.1.0 → selectools-1.2.0}/tests/test_mcp.py +0 -0
  260. {selectools-1.1.0 → selectools-1.2.0}/tests/test_mcp_coverage.py +0 -0
  261. {selectools-1.1.0 → selectools-1.2.0}/tests/test_memory.py +0 -0
  262. {selectools-1.1.0 → selectools-1.2.0}/tests/test_memory_async.py +0 -0
  263. {selectools-1.1.0 → selectools-1.2.0}/tests/test_memory_boundary.py +0 -0
  264. {selectools-1.1.0 → selectools-1.2.0}/tests/test_memory_integration.py +0 -0
  265. {selectools-1.1.0 → selectools-1.2.0}/tests/test_model_switching.py +0 -0
  266. {selectools-1.1.0 → selectools-1.2.0}/tests/test_multi_agent_edge_cases.py +0 -0
  267. {selectools-1.1.0 → selectools-1.2.0}/tests/test_multimodal.py +0 -0
  268. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_checkpoint.py +0 -0
  269. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_e2e.py +0 -0
  270. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_evals.py +0 -0
  271. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_graph.py +0 -0
  272. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_integration.py +0 -0
  273. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_primitives.py +0 -0
  274. {selectools-1.1.0 → selectools-1.2.0}/tests/test_orchestration_supervisor.py +0 -0
  275. {selectools-1.1.0 → selectools-1.2.0}/tests/test_otel_observer.py +0 -0
  276. {selectools-1.1.0 → selectools-1.2.0}/tests/test_parser.py +0 -0
  277. {selectools-1.1.0 → selectools-1.2.0}/tests/test_patterns.py +0 -0
  278. {selectools-1.1.0 → selectools-1.2.0}/tests/test_pending.py +0 -0
  279. {selectools-1.1.0 → selectools-1.2.0}/tests/test_pending_redis_smoke.py +0 -0
  280. {selectools-1.1.0 → selectools-1.2.0}/tests/test_phase1_design_patterns.py +0 -0
  281. {selectools-1.1.0 → selectools-1.2.0}/tests/test_pipeline.py +0 -0
  282. {selectools-1.1.0 → selectools-1.2.0}/tests/test_pipeline_coverage.py +0 -0
  283. {selectools-1.1.0 → selectools-1.2.0}/tests/test_policy.py +0 -0
  284. {selectools-1.1.0 → selectools-1.2.0}/tests/test_prompt.py +0 -0
  285. {selectools-1.1.0 → selectools-1.2.0}/tests/test_prompt_compression.py +0 -0
  286. {selectools-1.1.0 → selectools-1.2.0}/tests/test_property_based.py +0 -0
  287. {selectools-1.1.0 → selectools-1.2.0}/tests/test_reasoning_strategy.py +0 -0
  288. {selectools-1.1.0 → selectools-1.2.0}/tests/test_remaining_coverage.py +0 -0
  289. {selectools-1.1.0 → selectools-1.2.0}/tests/test_results.py +0 -0
  290. {selectools-1.1.0 → selectools-1.2.0}/tests/test_routing_mode.py +0 -0
  291. {selectools-1.1.0 → selectools-1.2.0}/tests/test_scheduler.py +0 -0
  292. {selectools-1.1.0 → selectools-1.2.0}/tests/test_security.py +0 -0
  293. {selectools-1.1.0 → selectools-1.2.0}/tests/test_semantic_cache.py +0 -0
  294. {selectools-1.1.0 → selectools-1.2.0}/tests/test_serve_cli.py +0 -0
  295. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions.py +0 -0
  296. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions_dynamodb.py +0 -0
  297. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions_edge_cases.py +0 -0
  298. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions_mongo.py +0 -0
  299. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions_redis.py +0 -0
  300. {selectools-1.1.0 → selectools-1.2.0}/tests/test_sessions_supabase.py +0 -0
  301. {selectools-1.1.0 → selectools-1.2.0}/tests/test_simple_observer.py +0 -0
  302. {selectools-1.1.0 → selectools-1.2.0}/tests/test_simulation_evals.py +0 -0
  303. {selectools-1.1.0 → selectools-1.2.0}/tests/test_ssrf.py +0 -0
  304. {selectools-1.1.0 → selectools-1.2.0}/tests/test_stability.py +0 -0
  305. {selectools-1.1.0 → selectools-1.2.0}/tests/test_starlette_app.py +0 -0
  306. {selectools-1.1.0 → selectools-1.2.0}/tests/test_structured.py +0 -0
  307. {selectools-1.1.0 → selectools-1.2.0}/tests/test_structured_config.py +0 -0
  308. {selectools-1.1.0 → selectools-1.2.0}/tests/test_structured_tool_results.py +0 -0
  309. {selectools-1.1.0 → selectools-1.2.0}/tests/test_summarize_on_trim.py +0 -0
  310. {selectools-1.1.0 → selectools-1.2.0}/tests/test_templates_coverage.py +0 -0
  311. {selectools-1.1.0 → selectools-1.2.0}/tests/test_terminal_actions.py +0 -0
  312. {selectools-1.1.0 → selectools-1.2.0}/tests/test_time.py +0 -0
  313. {selectools-1.1.0 → selectools-1.2.0}/tests/test_token_estimation.py +0 -0
  314. {selectools-1.1.0 → selectools-1.2.0}/tests/test_tool_caching.py +0 -0
  315. {selectools-1.1.0 → selectools-1.2.0}/tests/test_tool_result_compression.py +0 -0
  316. {selectools-1.1.0 → selectools-1.2.0}/tests/test_trace.py +0 -0
  317. {selectools-1.1.0 → selectools-1.2.0}/tests/test_trace_html.py +0 -0
  318. {selectools-1.1.0 → selectools-1.2.0}/tests/test_trace_store.py +0 -0
  319. {selectools-1.1.0 → selectools-1.2.0}/tests/test_unified_memory.py +0 -0
  320. {selectools-1.1.0 → selectools-1.2.0}/tests/test_unified_memory_config.py +0 -0
  321. {selectools-1.1.0 → selectools-1.2.0}/tests/test_v016_regression.py +0 -0
  322. {selectools-1.1.0 → selectools-1.2.0}/tests/test_v019_features.py +0 -0
  323. {selectools-1.1.0 → selectools-1.2.0}/tests/test_yaml_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selectools
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Production-ready Python framework for AI agents with multi-agent graphs, hybrid RAG, guardrails, audit logging, 50 evaluators, and a visual builder. Supports OpenAI, Anthropic, Gemini, Ollama. By NichevLabs.
5
5
  Author-email: John Nichev <johnnichev@gmail.com>
6
6
  Maintainer-email: NichevLabs <support@nichevlabs.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "selectools"
7
- version = "1.1.0"
7
+ version = "1.2.0"
8
8
  description = "Production-ready Python framework for AI agents with multi-agent graphs, hybrid RAG, guardrails, audit logging, 50 evaluators, and a visual builder. Supports OpenAI, Anthropic, Gemini, Ollama. By NichevLabs."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  """Public exports for the selectools package."""
2
2
 
3
- __version__ = "1.1.0"
3
+ __version__ = "1.2.0"
4
4
 
5
5
  # Import submodules (lazy loading for optional dependencies)
6
6
  from . import embeddings, evals, guardrails, models, observe, patterns, rag, toolbox
@@ -861,6 +861,11 @@ class _ToolExecutorMixin:
861
861
  cached_entry = self._check_tool_cache(tool, parameters)
862
862
  if cached_entry is not None:
863
863
  raw, compressed = cached_entry
864
+ # Guardrails run on cache hits too — an entry written before
865
+ # a guardrail was configured must not bypass the stage.
866
+ guarded = self._run_tool_result_guardrails(tool_name, raw, trace, run_ctx=run_ctx)
867
+ if guarded != raw:
868
+ raw, compressed = guarded, None
864
869
  return _Result(
865
870
  tc, raw, False, 0.0, tool, 0, cached=True, cached_compressed=compressed
866
871
  )
@@ -886,7 +891,10 @@ class _ToolExecutorMixin:
886
891
  try:
887
892
  result = self._execute_tool_with_timeout(tool, parameters, chunk_cb)
888
893
  result = self._screen_tool_result(tool_name, result)
894
+ # Cache the pre-guardrail value: guardrails run at use time
895
+ # (fresh AND cached), so config changes apply retroactively.
889
896
  self._store_tool_cache(tool, parameters, result)
897
+ result = self._run_tool_result_guardrails(tool_name, result, trace, run_ctx=run_ctx)
890
898
  dur = time.time() - start
891
899
  if run_id:
892
900
  self._notify_observers(
@@ -1103,6 +1111,13 @@ class _ToolExecutorMixin:
1103
1111
  cached_entry = self._check_tool_cache(tool, parameters)
1104
1112
  if cached_entry is not None:
1105
1113
  raw, compressed = cached_entry
1114
+ # Guardrails run on cache hits too — an entry written before
1115
+ # a guardrail was configured must not bypass the stage.
1116
+ guarded = await self._arun_tool_result_guardrails(
1117
+ tool_name, raw, trace, run_ctx=run_ctx
1118
+ )
1119
+ if guarded != raw:
1120
+ raw, compressed = guarded, None
1106
1121
  return _Result(
1107
1122
  tc, raw, False, 0.0, tool, 0, cached=True, cached_compressed=compressed
1108
1123
  )
@@ -1130,7 +1145,12 @@ class _ToolExecutorMixin:
1130
1145
  try:
1131
1146
  result = await self._aexecute_tool_with_timeout(tool, parameters, chunk_cb)
1132
1147
  result = self._screen_tool_result(tool_name, result)
1148
+ # Cache the pre-guardrail value: guardrails run at use time
1149
+ # (fresh AND cached), so config changes apply retroactively.
1133
1150
  self._store_tool_cache(tool, parameters, result)
1151
+ result = await self._arun_tool_result_guardrails(
1152
+ tool_name, result, trace, run_ctx=run_ctx
1153
+ )
1134
1154
  dur = time.time() - start
1135
1155
  if run_id:
1136
1156
  self._notify_observers(
@@ -1437,6 +1457,13 @@ class _ToolExecutorMixin:
1437
1457
  cached_entry = self._check_tool_cache(tool, parameters)
1438
1458
  if cached_entry is not None:
1439
1459
  cached_raw, cached_compressed = cached_entry
1460
+ # Guardrails run on cache hits too — an entry written before a
1461
+ # guardrail was configured must not bypass the stage.
1462
+ guarded = self._run_tool_result_guardrails(
1463
+ tool_name, cached_raw, ctx.trace, run_ctx=ctx
1464
+ )
1465
+ if guarded != cached_raw:
1466
+ cached_raw, cached_compressed = guarded, None
1440
1467
  ctx.trace.add(
1441
1468
  TraceStep(
1442
1469
  type=StepType.CACHE_HIT,
@@ -1475,15 +1502,16 @@ class _ToolExecutorMixin:
1475
1502
 
1476
1503
  result = self._execute_tool_with_timeout(tool, parameters, chunk_callback)
1477
1504
  result = self._screen_tool_result(tool_name, result)
1505
+ # Cache the pre-guardrail value: guardrails run at use time
1506
+ # (fresh AND cached), so config changes apply retroactively.
1507
+ self._store_tool_cache(tool, parameters, result)
1508
+ result = self._run_tool_result_guardrails(tool_name, result, ctx.trace, run_ctx=ctx)
1478
1509
  duration = time.time() - start_time
1479
1510
 
1480
1511
  self._notify_observers(
1481
1512
  "on_tool_end", ctx.run_id, call_id, tool_name, result, duration * 1000
1482
1513
  )
1483
1514
 
1484
- # Store in tool result cache
1485
- self._store_tool_cache(tool, parameters, result)
1486
-
1487
1515
  ctx.trace.add(
1488
1516
  TraceStep(
1489
1517
  type=StepType.TOOL_EXECUTION,
@@ -1673,6 +1701,13 @@ class _ToolExecutorMixin:
1673
1701
  cached_entry = self._check_tool_cache(tool, parameters)
1674
1702
  if cached_entry is not None:
1675
1703
  cached_raw, cached_compressed = cached_entry
1704
+ # Guardrails run on cache hits too — an entry written before a
1705
+ # guardrail was configured must not bypass the stage.
1706
+ guarded = await self._arun_tool_result_guardrails(
1707
+ tool_name, cached_raw, ctx.trace, run_ctx=ctx
1708
+ )
1709
+ if guarded != cached_raw:
1710
+ cached_raw, cached_compressed = guarded, None
1676
1711
  ctx.trace.add(
1677
1712
  TraceStep(
1678
1713
  type=StepType.CACHE_HIT,
@@ -1714,6 +1749,12 @@ class _ToolExecutorMixin:
1714
1749
 
1715
1750
  result = await self._aexecute_tool_with_timeout(tool, parameters, chunk_callback)
1716
1751
  result = self._screen_tool_result(tool_name, result)
1752
+ # Cache the pre-guardrail value: guardrails run at use time
1753
+ # (fresh AND cached), so config changes apply retroactively.
1754
+ self._store_tool_cache(tool, parameters, result)
1755
+ result = await self._arun_tool_result_guardrails(
1756
+ tool_name, result, ctx.trace, run_ctx=ctx
1757
+ )
1717
1758
  duration = time.time() - start_time
1718
1759
 
1719
1760
  self._notify_observers(
@@ -1723,9 +1764,6 @@ class _ToolExecutorMixin:
1723
1764
  "on_tool_end", ctx.run_id, call_id, tool_name, result, duration * 1000
1724
1765
  )
1725
1766
 
1726
- # Store in tool result cache
1727
- self._store_tool_cache(tool, parameters, result)
1728
-
1729
1767
  ctx.trace.add(
1730
1768
  TraceStep(
1731
1769
  type=StepType.TOOL_EXECUTION,
@@ -24,7 +24,7 @@ Usage::
24
24
  from __future__ import annotations
25
25
 
26
26
  from dataclasses import dataclass, field
27
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
27
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union
28
28
 
29
29
  from ..stability import beta, stable
30
30
 
@@ -37,6 +37,7 @@ if TYPE_CHECKING:
37
37
  from ..policy import ToolPolicy
38
38
  from ..providers.base import Provider
39
39
  from ..sessions import SessionStore
40
+ from ..types import Message
40
41
  from ..unified_memory import UnifiedMemory
41
42
 
42
43
 
@@ -192,12 +193,43 @@ class StructuredOutputConfig:
192
193
  produces the validated structured final answer. In ``astream()``
193
194
  the synthesis JSON is delivered only via the terminal
194
195
  ``AgentResult`` (``.content`` / ``.parsed``), never leaked as
195
- content chunks. Costs one extra provider call per run.
196
- Default: False.
196
+ content chunks. Costs at most one extra provider call per run
197
+ (see ``reuse_loop_answer`` / ``should_finalize`` /
198
+ ``single_pass`` for the paths that avoid it). Default: False.
199
+ reuse_loop_answer: In ``final_turn_only`` mode, when the loop's
200
+ converged answer validates against the schema, use it directly
201
+ and skip the synthesis call entirely (v1.2, issue #164). The
202
+ gate is conservative: the WHOLE answer must be a single JSON
203
+ object (fragments embedded in prose never qualify), Pydantic
204
+ schemas validate fully, and dict schemas must carry every
205
+ top-level ``required`` key. Anything else falls back to the
206
+ synthesis call. Default: True.
207
+ should_finalize: Optional predicate ``(messages, last_response_text)
208
+ -> bool`` consulted in ``final_turn_only`` mode when the
209
+ converged answer did NOT validate. Return ``False`` to skip the
210
+ synthesis call for turns that need no structured output — the
211
+ run finishes with ``parsed=None`` and
212
+ ``AgentResult.structured_status == "skipped"``. A validating
213
+ answer wins before the predicate runs (even with
214
+ ``reuse_loop_answer=False``). Like ``stop_condition``, an
215
+ exception raised by the predicate propagates and aborts the run.
216
+ Default: None (always finalize, the v1.1 behavior).
217
+ single_pass: In ``final_turn_only`` mode with a provider that
218
+ advertises ``supports_native_structured_output_with_tools``
219
+ (OpenAI/Azure), carry the schema natively on the loop calls so
220
+ the converged answer IS the structured object — combined with
221
+ ``reuse_loop_answer`` this eliminates the synthesis call (v1.2,
222
+ issue #166). Providers without combined support fall back to the
223
+ separate synthesis call. NOTE: in ``astream()`` the final answer
224
+ is then JSON and streams as content chunks (like plain native
225
+ mode). Default: False.
197
226
  """
198
227
 
199
228
  native: bool = True
200
229
  final_turn_only: bool = False
230
+ reuse_loop_answer: bool = True
231
+ should_finalize: Optional[Callable[[List["Message"], str], bool]] = None
232
+ single_pass: bool = False
201
233
 
202
234
 
203
235
  @stable