selectools 0.28.0__tar.gz → 0.29.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 (321) hide show
  1. {selectools-0.28.0/src/selectools.egg-info → selectools-0.29.0}/PKG-INFO +14 -1
  2. {selectools-0.28.0 → selectools-0.29.0}/README.md +13 -0
  3. {selectools-0.28.0 → selectools-0.29.0}/pyproject.toml +1 -1
  4. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/__init__.py +1 -1
  5. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/config.py +1 -1
  6. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/__init__.py +1 -1
  7. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/checkpoint.py +1 -1
  8. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/graph.py +1 -1
  9. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/node.py +1 -1
  10. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/state.py +1 -1
  11. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/supervisor.py +1 -1
  12. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/__init__.py +1 -1
  13. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/debate.py +1 -1
  14. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/plan_and_execute.py +1 -1
  15. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/reflective.py +1 -1
  16. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/team_lead.py +1 -1
  17. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/policy.py +1 -1
  18. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/sessions.py +1 -1
  19. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/calculator_tools.py +3 -3
  20. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/code_tools.py +3 -3
  21. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/db_tools.py +3 -3
  22. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/email_tools.py +3 -3
  23. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/github_tools.py +4 -4
  24. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/linear_tools.py +4 -4
  25. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/notion_tools.py +4 -4
  26. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/pdf_tools.py +3 -3
  27. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/search_tools.py +3 -3
  28. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/slack_tools.py +4 -4
  29. {selectools-0.28.0 → selectools-0.29.0/src/selectools.egg-info}/PKG-INFO +14 -1
  30. {selectools-0.28.0 → selectools-0.29.0}/tests/test_architecture.py +12 -12
  31. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_supabase.py +31 -0
  32. {selectools-0.28.0 → selectools-0.29.0}/LICENSE +0 -0
  33. {selectools-0.28.0 → selectools-0.29.0}/setup.cfg +0 -0
  34. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_async_utils.py +0 -0
  35. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_json_utils.py +0 -0
  36. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_ssrf.py +0 -0
  37. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/__init__.py +0 -0
  38. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/client.py +0 -0
  39. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/server.py +0 -0
  40. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/types.py +0 -0
  41. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/__init__.py +0 -0
  42. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_lifecycle.py +0 -0
  43. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_memory_manager.py +0 -0
  44. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_planning.py +0 -0
  45. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_provider_caller.py +0 -0
  46. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_tool_executor.py +0 -0
  47. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/config_groups.py +0 -0
  48. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/core.py +0 -0
  49. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/analytics.py +0 -0
  50. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/audit.py +0 -0
  51. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache.py +0 -0
  52. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache_redis.py +0 -0
  53. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache_semantic.py +0 -0
  54. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cancellation.py +0 -0
  55. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/checkpoint_postgres.py +0 -0
  56. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/coherence.py +0 -0
  57. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/compose.py +0 -0
  58. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/__init__.py +0 -0
  59. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/anthropic.py +0 -0
  60. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/cohere.py +0 -0
  61. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/gemini.py +0 -0
  62. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/openai.py +0 -0
  63. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/provider.py +0 -0
  64. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/entity_memory.py +0 -0
  65. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/env.py +0 -0
  66. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/__init__.py +0 -0
  67. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/__main__.py +0 -0
  68. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/badge.py +0 -0
  69. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/dataset.py +0 -0
  70. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/evaluators.py +0 -0
  71. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/generator.py +0 -0
  72. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/history.py +0 -0
  73. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/html.py +0 -0
  74. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/junit.py +0 -0
  75. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/llm_evaluators.py +0 -0
  76. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/pairwise.py +0 -0
  77. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/regression.py +0 -0
  78. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/report.py +0 -0
  79. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/serve.py +0 -0
  80. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/snapshot.py +0 -0
  81. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/suite.py +0 -0
  82. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/templates.py +0 -0
  83. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/types.py +0 -0
  84. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/exceptions.py +0 -0
  85. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/__init__.py +0 -0
  86. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/base.py +0 -0
  87. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/format.py +0 -0
  88. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/injection.py +0 -0
  89. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/length.py +0 -0
  90. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/pii.py +0 -0
  91. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/pipeline.py +0 -0
  92. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/topic.py +0 -0
  93. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/toxicity.py +0 -0
  94. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge.py +0 -0
  95. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_backends.py +0 -0
  96. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_graph.py +0 -0
  97. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_sanitizers.py +0 -0
  98. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_store_redis.py +0 -0
  99. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_store_supabase.py +0 -0
  100. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/loop_detection.py +0 -0
  101. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/__init__.py +0 -0
  102. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/_loop.py +0 -0
  103. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/bridge.py +0 -0
  104. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/client.py +0 -0
  105. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/config.py +0 -0
  106. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/multi.py +0 -0
  107. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/server.py +0 -0
  108. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/memory.py +0 -0
  109. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/models.py +0 -0
  110. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/__init__.py +0 -0
  111. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/langfuse.py +0 -0
  112. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/otel.py +0 -0
  113. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/trace_store.py +0 -0
  114. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observer.py +0 -0
  115. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/parser.py +0 -0
  116. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pending.py +0 -0
  117. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pipeline.py +0 -0
  118. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pricing.py +0 -0
  119. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/prompt.py +0 -0
  120. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/__init__.py +0 -0
  121. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/_openai_compat.py +0 -0
  122. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/anthropic_provider.py +0 -0
  123. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/azure_openai_provider.py +0 -0
  124. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/base.py +0 -0
  125. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/fallback.py +0 -0
  126. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/gemini_provider.py +0 -0
  127. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/litellm_provider.py +0 -0
  128. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/ollama_provider.py +0 -0
  129. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/openai_provider.py +0 -0
  130. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/router.py +0 -0
  131. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/stubs.py +0 -0
  132. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/__init__.py +0 -0
  133. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/bm25.py +0 -0
  134. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/chunking.py +0 -0
  135. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/hybrid.py +0 -0
  136. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/loaders.py +0 -0
  137. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/reranker.py +0 -0
  138. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/__init__.py +0 -0
  139. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/chroma.py +0 -0
  140. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/faiss.py +0 -0
  141. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/memory.py +0 -0
  142. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/pgvector.py +0 -0
  143. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/pinecone.py +0 -0
  144. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/qdrant.py +0 -0
  145. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/sqlite.py +0 -0
  146. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/tools.py +0 -0
  147. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/vector_store.py +0 -0
  148. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/results.py +0 -0
  149. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/scheduler.py +0 -0
  150. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/security.py +0 -0
  151. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/__init__.py +0 -0
  152. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_starlette_app.py +0 -0
  153. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.css +0 -0
  154. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.html +0 -0
  155. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.js +0 -0
  156. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/api.py +0 -0
  157. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/app.py +0 -0
  158. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/builder.py +0 -0
  159. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/cli.py +0 -0
  160. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/models.py +0 -0
  161. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/playground.py +0 -0
  162. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/stability.py +0 -0
  163. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/structured.py +0 -0
  164. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/__init__.py +0 -0
  165. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/code_reviewer.py +0 -0
  166. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/customer_support.py +0 -0
  167. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/data_analyst.py +0 -0
  168. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/rag_chatbot.py +0 -0
  169. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/research_assistant.py +0 -0
  170. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/token_estimation.py +0 -0
  171. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/__init__.py +0 -0
  172. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/browser_tools.py +0 -0
  173. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/data_tools.py +0 -0
  174. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/datetime_tools.py +0 -0
  175. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/discord_tools.py +0 -0
  176. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/file_tools.py +0 -0
  177. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/image_tools.py +0 -0
  178. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/memory_tools.py +0 -0
  179. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/reasoning_tools.py +0 -0
  180. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/s3_tools.py +0 -0
  181. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/text_tools.py +0 -0
  182. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/web_tools.py +0 -0
  183. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/__init__.py +0 -0
  184. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/base.py +0 -0
  185. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/decorators.py +0 -0
  186. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/loader.py +0 -0
  187. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/registry.py +0 -0
  188. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/trace.py +0 -0
  189. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/types.py +0 -0
  190. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/unified_memory.py +0 -0
  191. {selectools-0.28.0 → selectools-0.29.0}/src/selectools/usage.py +0 -0
  192. {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/SOURCES.txt +0 -0
  193. {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/dependency_links.txt +0 -0
  194. {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/entry_points.txt +0 -0
  195. {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/requires.txt +0 -0
  196. {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/top_level.txt +0 -0
  197. {selectools-0.28.0 → selectools-0.29.0}/tests/test_a2a.py +0 -0
  198. {selectools-0.28.0 → selectools-0.29.0}/tests/test_agent_api.py +0 -0
  199. {selectools-0.28.0 → selectools-0.29.0}/tests/test_agent_hitl.py +0 -0
  200. {selectools-0.28.0 → selectools-0.29.0}/tests/test_approval_gate.py +0 -0
  201. {selectools-0.28.0 → selectools-0.29.0}/tests/test_async_observers.py +0 -0
  202. {selectools-0.28.0 → selectools-0.29.0}/tests/test_audit.py +0 -0
  203. {selectools-0.28.0 → selectools-0.29.0}/tests/test_bake_window_hunt.py +0 -0
  204. {selectools-0.28.0 → selectools-0.29.0}/tests/test_budget.py +0 -0
  205. {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_core.py +0 -0
  206. {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_security.py +0 -0
  207. {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_tools.py +0 -0
  208. {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_regression.py +0 -0
  209. {selectools-0.28.0 → selectools-0.29.0}/tests/test_cache.py +0 -0
  210. {selectools-0.28.0 → selectools-0.29.0}/tests/test_cache_redis.py +0 -0
  211. {selectools-0.28.0 → selectools-0.29.0}/tests/test_cancellation.py +0 -0
  212. {selectools-0.28.0 → selectools-0.29.0}/tests/test_checkpoint_postgres.py +0 -0
  213. {selectools-0.28.0 → selectools-0.29.0}/tests/test_coherence.py +0 -0
  214. {selectools-0.28.0 → selectools-0.29.0}/tests/test_concurrency_smoke.py +0 -0
  215. {selectools-0.28.0 → selectools-0.29.0}/tests/test_consolidation_regression.py +0 -0
  216. {selectools-0.28.0 → selectools-0.29.0}/tests/test_conversation_branching.py +0 -0
  217. {selectools-0.28.0 → selectools-0.29.0}/tests/test_coverage_orchestration.py +0 -0
  218. {selectools-0.28.0 → selectools-0.29.0}/tests/test_document_loaders_extended.py +0 -0
  219. {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_langfuse_observer.py +0 -0
  220. {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_multimodal.py +0 -0
  221. {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_otel_observer.py +0 -0
  222. {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_v0_21_0_apps.py +0 -0
  223. {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_v0_21_0_simulations.py +0 -0
  224. {selectools-0.28.0 → selectools-0.29.0}/tests/test_entity_memory.py +0 -0
  225. {selectools-0.28.0 → selectools-0.29.0}/tests/test_env.py +0 -0
  226. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals.py +0 -0
  227. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_advanced.py +0 -0
  228. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_cli.py +0 -0
  229. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_e2e.py +0 -0
  230. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_final.py +0 -0
  231. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_hardening.py +0 -0
  232. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_html_report.py +0 -0
  233. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_new_evaluators.py +0 -0
  234. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_ralph_bugs.py +0 -0
  235. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_release.py +0 -0
  236. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_serve.py +0 -0
  237. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_v017_features.py +0 -0
  238. {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_v0191.py +0 -0
  239. {selectools-0.28.0 → selectools-0.29.0}/tests/test_features_in_graph.py +0 -0
  240. {selectools-0.28.0 → selectools-0.29.0}/tests/test_final_coverage_a.py +0 -0
  241. {selectools-0.28.0 → selectools-0.29.0}/tests/test_final_coverage_b.py +0 -0
  242. {selectools-0.28.0 → selectools-0.29.0}/tests/test_guardrails.py +0 -0
  243. {selectools-0.28.0 → selectools-0.29.0}/tests/test_guardrails_injection.py +0 -0
  244. {selectools-0.28.0 → selectools-0.29.0}/tests/test_hardening.py +0 -0
  245. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge.py +0 -0
  246. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend.py +0 -0
  247. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend_redis.py +0 -0
  248. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend_supabase.py +0 -0
  249. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_graph.py +0 -0
  250. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_sanitizers.py +0 -0
  251. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_store_redis.py +0 -0
  252. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_store_supabase.py +0 -0
  253. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_stores.py +0 -0
  254. {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_stores_error_handling.py +0 -0
  255. {selectools-0.28.0 → selectools-0.29.0}/tests/test_langfuse_observer.py +0 -0
  256. {selectools-0.28.0 → selectools-0.29.0}/tests/test_loop_detection.py +0 -0
  257. {selectools-0.28.0 → selectools-0.29.0}/tests/test_mcp.py +0 -0
  258. {selectools-0.28.0 → selectools-0.29.0}/tests/test_mcp_coverage.py +0 -0
  259. {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory.py +0 -0
  260. {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_async.py +0 -0
  261. {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_boundary.py +0 -0
  262. {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_integration.py +0 -0
  263. {selectools-0.28.0 → selectools-0.29.0}/tests/test_model_switching.py +0 -0
  264. {selectools-0.28.0 → selectools-0.29.0}/tests/test_multi_agent_edge_cases.py +0 -0
  265. {selectools-0.28.0 → selectools-0.29.0}/tests/test_multimodal.py +0 -0
  266. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_checkpoint.py +0 -0
  267. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_e2e.py +0 -0
  268. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_evals.py +0 -0
  269. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_graph.py +0 -0
  270. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_integration.py +0 -0
  271. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_primitives.py +0 -0
  272. {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_supervisor.py +0 -0
  273. {selectools-0.28.0 → selectools-0.29.0}/tests/test_otel_observer.py +0 -0
  274. {selectools-0.28.0 → selectools-0.29.0}/tests/test_parser.py +0 -0
  275. {selectools-0.28.0 → selectools-0.29.0}/tests/test_patterns.py +0 -0
  276. {selectools-0.28.0 → selectools-0.29.0}/tests/test_pending.py +0 -0
  277. {selectools-0.28.0 → selectools-0.29.0}/tests/test_pending_redis_smoke.py +0 -0
  278. {selectools-0.28.0 → selectools-0.29.0}/tests/test_phase1_design_patterns.py +0 -0
  279. {selectools-0.28.0 → selectools-0.29.0}/tests/test_pipeline.py +0 -0
  280. {selectools-0.28.0 → selectools-0.29.0}/tests/test_pipeline_coverage.py +0 -0
  281. {selectools-0.28.0 → selectools-0.29.0}/tests/test_policy.py +0 -0
  282. {selectools-0.28.0 → selectools-0.29.0}/tests/test_prompt.py +0 -0
  283. {selectools-0.28.0 → selectools-0.29.0}/tests/test_prompt_compression.py +0 -0
  284. {selectools-0.28.0 → selectools-0.29.0}/tests/test_property_based.py +0 -0
  285. {selectools-0.28.0 → selectools-0.29.0}/tests/test_reasoning_strategy.py +0 -0
  286. {selectools-0.28.0 → selectools-0.29.0}/tests/test_remaining_coverage.py +0 -0
  287. {selectools-0.28.0 → selectools-0.29.0}/tests/test_results.py +0 -0
  288. {selectools-0.28.0 → selectools-0.29.0}/tests/test_routing_mode.py +0 -0
  289. {selectools-0.28.0 → selectools-0.29.0}/tests/test_scheduler.py +0 -0
  290. {selectools-0.28.0 → selectools-0.29.0}/tests/test_security.py +0 -0
  291. {selectools-0.28.0 → selectools-0.29.0}/tests/test_semantic_cache.py +0 -0
  292. {selectools-0.28.0 → selectools-0.29.0}/tests/test_serve_app_coverage.py +0 -0
  293. {selectools-0.28.0 → selectools-0.29.0}/tests/test_serve_cli.py +0 -0
  294. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions.py +0 -0
  295. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_dynamodb.py +0 -0
  296. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_edge_cases.py +0 -0
  297. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_mongo.py +0 -0
  298. {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_redis.py +0 -0
  299. {selectools-0.28.0 → selectools-0.29.0}/tests/test_simple_observer.py +0 -0
  300. {selectools-0.28.0 → selectools-0.29.0}/tests/test_simulation_evals.py +0 -0
  301. {selectools-0.28.0 → selectools-0.29.0}/tests/test_ssrf.py +0 -0
  302. {selectools-0.28.0 → selectools-0.29.0}/tests/test_stability.py +0 -0
  303. {selectools-0.28.0 → selectools-0.29.0}/tests/test_starlette_app.py +0 -0
  304. {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured.py +0 -0
  305. {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured_config.py +0 -0
  306. {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured_tool_results.py +0 -0
  307. {selectools-0.28.0 → selectools-0.29.0}/tests/test_summarize_on_trim.py +0 -0
  308. {selectools-0.28.0 → selectools-0.29.0}/tests/test_templates_coverage.py +0 -0
  309. {selectools-0.28.0 → selectools-0.29.0}/tests/test_terminal_actions.py +0 -0
  310. {selectools-0.28.0 → selectools-0.29.0}/tests/test_token_estimation.py +0 -0
  311. {selectools-0.28.0 → selectools-0.29.0}/tests/test_tool_caching.py +0 -0
  312. {selectools-0.28.0 → selectools-0.29.0}/tests/test_tool_result_compression.py +0 -0
  313. {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace.py +0 -0
  314. {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace_html.py +0 -0
  315. {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace_store.py +0 -0
  316. {selectools-0.28.0 → selectools-0.29.0}/tests/test_unified_memory.py +0 -0
  317. {selectools-0.28.0 → selectools-0.29.0}/tests/test_unified_memory_config.py +0 -0
  318. {selectools-0.28.0 → selectools-0.29.0}/tests/test_v016_regression.py +0 -0
  319. {selectools-0.28.0 → selectools-0.29.0}/tests/test_v019_features.py +0 -0
  320. {selectools-0.28.0 → selectools-0.29.0}/tests/test_visual_builder.py +0 -0
  321. {selectools-0.28.0 → selectools-0.29.0}/tests/test_yaml_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selectools
3
- Version: 0.28.0
3
+ Version: 0.29.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>
@@ -118,6 +118,19 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
118
118
  # selectools serve agent.yaml
119
119
  ```
120
120
 
121
+ ## What's New in v0.29
122
+
123
+ ### v0.29.0 — Stability Promotions (v1.0 Freeze Prep)
124
+
125
+ The first beta → stable promotion pass toward the 1.0 API freeze. Additive only — promotions strengthen guarantees, nothing is removed or renamed.
126
+
127
+ - **24 mature toolbox tools promoted to `@stable`** — calculator, code (incl. `execute_shell`), db, email, GitHub, Linear, Notion, PDF, web search, and Slack tools. They're 4–15 releases old with frozen signatures.
128
+ - **`orchestration`, `patterns`, and `policy` are now stable modules** — their public surfaces (AgentGraph, the checkpoint stores, all five pattern agents, ToolPolicy) were already frozen in v0.25; this aligns the module-level promise. Also promoted `SessionSearchResult` and `PlanningConfig`.
129
+ - **Held `@beta` on purpose** — the v0.27.0 additions (recall tool, injection guardrail, cache-rate cost, Mongo/Dynamo session stores) get one more cycle, and `evals` stays a beta module while its 50 evaluator classes keep growing (its 7 core types are `@stable`).
130
+ - **New `scripts/stability_audit.py`** reports any symbol whose marker disagrees with its module promise, so promotion passes are reproducible.
131
+
132
+ See `CHANGELOG.md` for the full entry.
133
+
121
134
  ## What's New in v0.28
122
135
 
123
136
  ### v0.28.0 — Hardening Sweep: Shell Safety, Session Namespaces & Typed Public API
@@ -30,6 +30,19 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
30
30
  # selectools serve agent.yaml
31
31
  ```
32
32
 
33
+ ## What's New in v0.29
34
+
35
+ ### v0.29.0 — Stability Promotions (v1.0 Freeze Prep)
36
+
37
+ The first beta → stable promotion pass toward the 1.0 API freeze. Additive only — promotions strengthen guarantees, nothing is removed or renamed.
38
+
39
+ - **24 mature toolbox tools promoted to `@stable`** — calculator, code (incl. `execute_shell`), db, email, GitHub, Linear, Notion, PDF, web search, and Slack tools. They're 4–15 releases old with frozen signatures.
40
+ - **`orchestration`, `patterns`, and `policy` are now stable modules** — their public surfaces (AgentGraph, the checkpoint stores, all five pattern agents, ToolPolicy) were already frozen in v0.25; this aligns the module-level promise. Also promoted `SessionSearchResult` and `PlanningConfig`.
41
+ - **Held `@beta` on purpose** — the v0.27.0 additions (recall tool, injection guardrail, cache-rate cost, Mongo/Dynamo session stores) get one more cycle, and `evals` stays a beta module while its 50 evaluator classes keep growing (its 7 core types are `@stable`).
42
+ - **New `scripts/stability_audit.py`** reports any symbol whose marker disagrees with its module promise, so promotion passes are reproducible.
43
+
44
+ See `CHANGELOG.md` for the full entry.
45
+
33
46
  ## What's New in v0.28
34
47
 
35
48
  ### v0.28.0 — Hardening Sweep: Shell Safety, Session Namespaces & Typed Public API
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "selectools"
7
- version = "0.28.0"
7
+ version = "0.29.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.9"
@@ -1,6 +1,6 @@
1
1
  """Public exports for the selectools package."""
2
2
 
3
- __version__ = "0.28.0"
3
+ __version__ = "0.29.0"
4
4
 
5
5
  # Import submodules (lazy loading for optional dependencies)
6
6
  from . import embeddings, evals, guardrails, models, observe, patterns, rag, toolbox
@@ -404,7 +404,7 @@ step executes and must return one of:
404
404
  """
405
405
 
406
406
 
407
- @beta
407
+ @stable
408
408
  @dataclass
409
409
  class PlanningConfig:
410
410
  """Opt-in planning for any Agent: plan -> (approve) -> execute -> synthesize.
@@ -58,7 +58,7 @@ from .state import (
58
58
  )
59
59
  from .supervisor import ModelSplit, SupervisorAgent, SupervisorStrategy
60
60
 
61
- __stability__ = "beta"
61
+ __stability__ = "stable"
62
62
 
63
63
  __all__ = [
64
64
  # Core graph
@@ -392,7 +392,7 @@ class SQLiteCheckpointStore:
392
392
  # for implementations that do not define it, so it is registered instead.
393
393
  register_stability("CheckpointStore", "stable")
394
394
 
395
- __stability__ = "beta"
395
+ __stability__ = "stable"
396
396
 
397
397
  __all__ = [
398
398
  "CheckpointMetadata",
@@ -1828,7 +1828,7 @@ class AgentGraph:
1828
1828
  print()
1829
1829
 
1830
1830
 
1831
- __stability__ = "beta"
1831
+ __stability__ = "stable"
1832
1832
 
1833
1833
  __all__ = [
1834
1834
  "AgentGraph",
@@ -183,7 +183,7 @@ def build_context_messages(node: GraphNode, state: GraphState) -> List[Any]:
183
183
  return default_input_transform(state)
184
184
 
185
185
 
186
- __stability__ = "beta"
186
+ __stability__ = "stable"
187
187
 
188
188
  __all__ = [
189
189
  "GraphNode",
@@ -342,7 +342,7 @@ def merge_states(states: List[GraphState], policy: MergePolicy) -> GraphState:
342
342
  )
343
343
 
344
344
 
345
- __stability__ = "beta"
345
+ __stability__ = "stable"
346
346
 
347
347
  __all__ = [
348
348
  "STATE_KEY_LAST_OUTPUT",
@@ -605,7 +605,7 @@ def _format_history(history: List[Any]) -> str:
605
605
  return "\n".join(lines) if lines else "No steps taken yet."
606
606
 
607
607
 
608
- __stability__ = "beta"
608
+ __stability__ = "stable"
609
609
 
610
610
  __all__ = [
611
611
  "SupervisorAgent",
@@ -25,7 +25,7 @@ from .plan_and_execute import PlanAndExecuteAgent, PlanStep
25
25
  from .reflective import ReflectionRound, ReflectiveAgent, ReflectiveResult
26
26
  from .team_lead import Subtask, TeamLeadAgent, TeamLeadResult
27
27
 
28
- __stability__ = "beta"
28
+ __stability__ = "stable"
29
29
 
30
30
  __all__ = [
31
31
  # PlanAndExecute
@@ -133,6 +133,6 @@ class DebateAgent:
133
133
  return DebateResult(conclusion=conclusion, rounds=rounds)
134
134
 
135
135
 
136
- __stability__ = "beta"
136
+ __stability__ = "stable"
137
137
 
138
138
  __all__ = ["DebateAgent", "DebateRound", "DebateResult"]
@@ -222,6 +222,6 @@ class PlanAndExecuteAgent:
222
222
  return steps
223
223
 
224
224
 
225
- __stability__ = "beta"
225
+ __stability__ = "stable"
226
226
 
227
227
  __all__ = ["PlanAndExecuteAgent", "PlanStep"]
@@ -135,6 +135,6 @@ class ReflectiveAgent:
135
135
  return ReflectiveResult(final_draft=draft, rounds=rounds, approved=approved)
136
136
 
137
137
 
138
- __stability__ = "beta"
138
+ __stability__ = "stable"
139
139
 
140
140
  __all__ = ["ReflectiveAgent", "ReflectionRound", "ReflectiveResult"]
@@ -305,6 +305,6 @@ class TeamLeadAgent:
305
305
  return TeamLeadResult(content=synthesis.content or work_log, subtasks=all_subtasks)
306
306
 
307
307
 
308
- __stability__ = "beta"
308
+ __stability__ = "stable"
309
309
 
310
310
  __all__ = ["TeamLeadAgent", "Subtask", "TeamLeadResult"]
@@ -233,6 +233,6 @@ class ToolPolicy:
233
233
  return cls.from_dict(data)
234
234
 
235
235
 
236
- __stability__ = "beta"
236
+ __stability__ = "stable"
237
237
 
238
238
  __all__ = ["ApprovalRequest", "ToolPolicy", "PolicyDecision", "PolicyResult"]
@@ -53,7 +53,7 @@ class SessionMetadata:
53
53
  updated_at: float
54
54
 
55
55
 
56
- @beta
56
+ @stable
57
57
  @dataclass(frozen=True)
58
58
  class SessionSearchResult:
59
59
  """One session matched by :meth:`SessionStore.search`.
@@ -17,7 +17,7 @@ import ast
17
17
  import math
18
18
  from typing import Callable, Dict, Union
19
19
 
20
- from ..stability import beta
20
+ from ..stability import stable
21
21
  from ..tools import tool
22
22
 
23
23
  _MAX_EXPRESSION_LENGTH = 2000
@@ -144,7 +144,7 @@ def _eval_node(node: ast.AST) -> _Number:
144
144
  raise ValueError(f"expression element '{type(node).__name__}' is not allowed")
145
145
 
146
146
 
147
- @beta
147
+ @stable
148
148
  @tool(description="Safely evaluate a math expression (arithmetic, sqrt, log, trig, pi/e)")
149
149
  def evaluate_expression(expression: str) -> str:
150
150
  """
@@ -279,7 +279,7 @@ def _format_quantity(value: float) -> str:
279
279
  return f"{value:.6f}".rstrip("0").rstrip(".")
280
280
 
281
281
 
282
- @beta
282
+ @stable
283
283
  @tool(description="Convert between length, mass, temperature, and data units")
284
284
  def unit_convert(value: float, from_unit: str, to_unit: str) -> str:
285
285
  """
@@ -12,7 +12,7 @@ import shlex
12
12
  import subprocess # nosec B404 — code execution tool
13
13
  import tempfile
14
14
 
15
- from ..stability import beta
15
+ from ..stability import stable
16
16
  from ..tools import tool
17
17
 
18
18
  _MAX_OUTPUT_BYTES = 10 * 1024 # 10 KB
@@ -47,7 +47,7 @@ def _truncate(text: str, max_bytes: int = _MAX_OUTPUT_BYTES) -> str:
47
47
  return truncated + "\n... (output truncated to 10 KB)"
48
48
 
49
49
 
50
- @beta
50
+ @stable
51
51
  @tool(description="Execute Python code and return stdout + stderr")
52
52
  def execute_python(code: str, timeout: int = 30) -> str:
53
53
  """
@@ -114,7 +114,7 @@ def execute_python(code: str, timeout: int = 30) -> str:
114
114
  os.unlink(tmp_path)
115
115
 
116
116
 
117
- @beta
117
+ @stable
118
118
  @tool(description="Execute a shell command and return output")
119
119
  def execute_shell(command: str, timeout: int = 30) -> str:
120
120
  """
@@ -11,7 +11,7 @@ import os
11
11
  import re
12
12
  import sqlite3
13
13
 
14
- from ..stability import beta
14
+ from ..stability import stable
15
15
  from ..tools import tool
16
16
 
17
17
 
@@ -64,7 +64,7 @@ def _format_table(columns: list[str], rows: list[tuple]) -> str:
64
64
  return "\n".join(lines)
65
65
 
66
66
 
67
- @beta
67
+ @stable
68
68
  @tool(description="Execute a read-only SQL query against a SQLite database")
69
69
  def query_sqlite(db_path: str, sql: str, max_rows: int = 100) -> str:
70
70
  """
@@ -130,7 +130,7 @@ def query_sqlite(db_path: str, sql: str, max_rows: int = 100) -> str:
130
130
  conn.close()
131
131
 
132
132
 
133
- @beta
133
+ @stable
134
134
  @tool(description="Execute a read-only SQL query against PostgreSQL")
135
135
  def query_postgres(connection_string: str, sql: str, max_rows: int = 100) -> str:
136
136
  """
@@ -20,7 +20,7 @@ from email.message import EmailMessage
20
20
  from email.utils import parsedate_to_datetime
21
21
  from typing import Optional
22
22
 
23
- from ..stability import beta
23
+ from ..stability import stable
24
24
  from ..tools import tool
25
25
 
26
26
  _DEFAULT_SMTP_PORT = 587
@@ -62,7 +62,7 @@ def _extract_snippet(message: "EmailMessage") -> str:
62
62
  return snippet
63
63
 
64
64
 
65
- @beta
65
+ @stable
66
66
  @tool(description="Send an email via SMTP (TLS)")
67
67
  def send_email(
68
68
  to: str,
@@ -140,7 +140,7 @@ def send_email(
140
140
  return f"Error: Could not connect to SMTP server {host}:{port}: {exc}"
141
141
 
142
142
 
143
- @beta
143
+ @stable
144
144
  @tool(description="Read the latest emails from an IMAP inbox")
145
145
  def read_inbox(
146
146
  limit: int = 5,
@@ -15,7 +15,7 @@ import urllib.parse
15
15
  import urllib.request
16
16
  from typing import Any
17
17
 
18
- from ..stability import beta
18
+ from ..stability import stable
19
19
  from ..tools import tool
20
20
 
21
21
  _API_BASE = "https://api.github.com"
@@ -49,7 +49,7 @@ def _github_request(path: str, params: dict[str, str] | None = None) -> Any:
49
49
  return json.loads(resp.read().decode("utf-8"))
50
50
 
51
51
 
52
- @beta
52
+ @stable
53
53
  @tool(description="Search GitHub repositories")
54
54
  def github_search_repos(query: str, max_results: int = 5) -> str:
55
55
  """
@@ -107,7 +107,7 @@ def github_search_repos(query: str, max_results: int = 5) -> str:
107
107
  return f"Error searching GitHub: {e}"
108
108
 
109
109
 
110
- @beta
110
+ @stable
111
111
  @tool(description="Get file contents from a GitHub repository")
112
112
  def github_get_file(repo: str, path: str, ref: str = "main") -> str:
113
113
  """
@@ -180,7 +180,7 @@ def github_get_file(repo: str, path: str, ref: str = "main") -> str:
180
180
  return f"Error fetching file: {e}"
181
181
 
182
182
 
183
- @beta
183
+ @stable
184
184
  @tool(description="List issues in a GitHub repository")
185
185
  def github_list_issues(repo: str, state: str = "open", max_results: int = 10) -> str:
186
186
  """
@@ -16,7 +16,7 @@ import json
16
16
  import os
17
17
  from typing import Any, Dict, Optional
18
18
 
19
- from ..stability import beta
19
+ from ..stability import stable
20
20
  from ..tools import tool
21
21
 
22
22
  _API_URL = "https://api.linear.app/graphql"
@@ -57,7 +57,7 @@ def _format_graphql_errors(body: Dict[str, Any]) -> str:
57
57
  return f"Error: Linear API error: {messages}"
58
58
 
59
59
 
60
- @beta
60
+ @stable
61
61
  @tool(description="Create an issue in Linear")
62
62
  def linear_create_issue(
63
63
  team_id: str,
@@ -127,7 +127,7 @@ def linear_create_issue(
127
127
  return f"Error creating Linear issue: {type(exc).__name__}: {exc}"
128
128
 
129
129
 
130
- @beta
130
+ @stable
131
131
  @tool(description="List recent issues in Linear")
132
132
  def linear_list_issues(
133
133
  team_id: Optional[str] = None,
@@ -206,7 +206,7 @@ def linear_list_issues(
206
206
  return f"Error listing Linear issues: {type(exc).__name__}: {exc}"
207
207
 
208
208
 
209
- @beta
209
+ @stable
210
210
  @tool(description="Update a Linear issue's title, description, or state")
211
211
  def linear_update_issue(
212
212
  issue_id: str,
@@ -17,7 +17,7 @@ import json
17
17
  import os
18
18
  from typing import Any, Dict, Optional
19
19
 
20
- from ..stability import beta
20
+ from ..stability import stable
21
21
  from ..tools import tool
22
22
 
23
23
  _API_BASE = "https://api.notion.com/v1"
@@ -53,7 +53,7 @@ def _api_error(response: Any) -> str:
53
53
  return f"Error: Notion API returned HTTP {response.status_code}{detail}"
54
54
 
55
55
 
56
- @beta
56
+ @stable
57
57
  @tool(description="Create a page in Notion")
58
58
  def notion_create_page(
59
59
  parent_page_id: str,
@@ -123,7 +123,7 @@ def notion_create_page(
123
123
  return f"Error creating Notion page: {type(exc).__name__}: {exc}"
124
124
 
125
125
 
126
- @beta
126
+ @stable
127
127
  @tool(description="Search pages and databases in a Notion workspace")
128
128
  def notion_search(query: str, max_results: int = 5, api_key: Optional[str] = None) -> str:
129
129
  """
@@ -195,7 +195,7 @@ def notion_search(query: str, max_results: int = 5, api_key: Optional[str] = Non
195
195
  return f"Error searching Notion: {type(exc).__name__}: {exc}"
196
196
 
197
197
 
198
- @beta
198
+ @stable
199
199
  @tool(description="Update a Notion page's title or archive state")
200
200
  def notion_update_page(
201
201
  page_id: str,
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
  from pathlib import Path
13
13
  from typing import List, Optional
14
14
 
15
- from ..stability import beta
15
+ from ..stability import stable
16
16
  from ..tools import tool
17
17
 
18
18
  _MAX_OUTPUT_CHARS = 20_000
@@ -49,7 +49,7 @@ def _parse_page_spec(pages: Optional[str], page_count: int) -> List[int]:
49
49
  return sorted(set(selected))
50
50
 
51
51
 
52
- @beta
52
+ @stable
53
53
  @tool(description="Extract text content from a PDF file")
54
54
  def extract_pdf_text(path: str, pages: Optional[str] = None) -> str:
55
55
  """
@@ -97,7 +97,7 @@ def extract_pdf_text(path: str, pages: Optional[str] = None) -> str:
97
97
  return f"Error reading PDF: {type(exc).__name__}: {exc}"
98
98
 
99
99
 
100
- @beta
100
+ @stable
101
101
  @tool(description="Extract tables from a PDF file")
102
102
  def extract_pdf_tables(path: str, pages: Optional[str] = None) -> str:
103
103
  """
@@ -14,7 +14,7 @@ import urllib.request
14
14
  from typing import Optional
15
15
 
16
16
  from .._ssrf import validate_url as _validate_url
17
- from ..stability import beta
17
+ from ..stability import stable
18
18
  from ..tools import tool
19
19
 
20
20
  _MAX_OUTPUT_BYTES = 10 * 1024 # 10 KB
@@ -43,7 +43,7 @@ def _strip_html_tags(text: str) -> str:
43
43
  return text.strip()
44
44
 
45
45
 
46
- @beta
46
+ @stable
47
47
  @tool(description="Search the web using DuckDuckGo (no API key needed)")
48
48
  def web_search(query: str, num_results: int = 5) -> str:
49
49
  """
@@ -121,7 +121,7 @@ def web_search(query: str, num_results: int = 5) -> str:
121
121
  return f"Error performing web search: {e}"
122
122
 
123
123
 
124
- @beta
124
+ @stable
125
125
  @tool(description="Fetch a URL and extract text content")
126
126
  def scrape_url(url: str, selector: Optional[str] = None) -> str:
127
127
  """
@@ -17,7 +17,7 @@ from __future__ import annotations
17
17
  import os
18
18
  from typing import Any, Optional
19
19
 
20
- from ..stability import beta
20
+ from ..stability import stable
21
21
  from ..tools import tool
22
22
 
23
23
  _MISSING_DEP_ERROR = (
@@ -46,7 +46,7 @@ def _slack_error(exc: Any) -> str:
46
46
  return f"Error: Slack API call failed: {type(exc).__name__}"
47
47
 
48
48
 
49
- @beta
49
+ @stable
50
50
  @tool(description="Send a message to a Slack channel")
51
51
  def slack_send_message(channel: str, text: str, token: Optional[str] = None) -> str:
52
52
  """
@@ -88,7 +88,7 @@ def slack_send_message(channel: str, text: str, token: Optional[str] = None) ->
88
88
  return f"Error sending Slack message: {type(exc).__name__}"
89
89
 
90
90
 
91
- @beta
91
+ @stable
92
92
  @tool(description="Read recent messages from a Slack channel")
93
93
  def slack_read_channel(channel: str, limit: int = 10, token: Optional[str] = None) -> str:
94
94
  """
@@ -144,7 +144,7 @@ def slack_read_channel(channel: str, limit: int = 10, token: Optional[str] = Non
144
144
  return f"Error reading Slack channel: {type(exc).__name__}"
145
145
 
146
146
 
147
- @beta
147
+ @stable
148
148
  @tool(description="Search Slack messages across the workspace")
149
149
  def slack_search_messages(query: str, count: int = 10, token: Optional[str] = None) -> str:
150
150
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selectools
3
- Version: 0.28.0
3
+ Version: 0.29.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>
@@ -118,6 +118,19 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
118
118
  # selectools serve agent.yaml
119
119
  ```
120
120
 
121
+ ## What's New in v0.29
122
+
123
+ ### v0.29.0 — Stability Promotions (v1.0 Freeze Prep)
124
+
125
+ The first beta → stable promotion pass toward the 1.0 API freeze. Additive only — promotions strengthen guarantees, nothing is removed or renamed.
126
+
127
+ - **24 mature toolbox tools promoted to `@stable`** — calculator, code (incl. `execute_shell`), db, email, GitHub, Linear, Notion, PDF, web search, and Slack tools. They're 4–15 releases old with frozen signatures.
128
+ - **`orchestration`, `patterns`, and `policy` are now stable modules** — their public surfaces (AgentGraph, the checkpoint stores, all five pattern agents, ToolPolicy) were already frozen in v0.25; this aligns the module-level promise. Also promoted `SessionSearchResult` and `PlanningConfig`.
129
+ - **Held `@beta` on purpose** — the v0.27.0 additions (recall tool, injection guardrail, cache-rate cost, Mongo/Dynamo session stores) get one more cycle, and `evals` stays a beta module while its 50 evaluator classes keep growing (its 7 core types are `@stable`).
130
+ - **New `scripts/stability_audit.py`** reports any symbol whose marker disagrees with its module promise, so promotion passes are reproducible.
131
+
132
+ See `CHANGELOG.md` for the full entry.
133
+
121
134
  ## What's New in v0.28
122
135
 
123
136
  ### v0.28.0 — Hardening Sweep: Shell Safety, Session Namespaces & Typed Public API
@@ -511,21 +511,21 @@ EXPECTED_MODULE_STABILITY = {
511
511
  "observe.otel": "beta",
512
512
  "observe.trace_store": "beta",
513
513
  "observer": "stable",
514
- "orchestration": "beta",
515
- "orchestration.checkpoint": "beta",
516
- "orchestration.graph": "beta",
517
- "orchestration.node": "beta",
518
- "orchestration.state": "beta",
519
- "orchestration.supervisor": "beta",
514
+ "orchestration": "stable",
515
+ "orchestration.checkpoint": "stable",
516
+ "orchestration.graph": "stable",
517
+ "orchestration.node": "stable",
518
+ "orchestration.state": "stable",
519
+ "orchestration.supervisor": "stable",
520
520
  "parser": "stable",
521
- "patterns": "beta",
522
- "patterns.debate": "beta",
523
- "patterns.plan_and_execute": "beta",
524
- "patterns.reflective": "beta",
525
- "patterns.team_lead": "beta",
521
+ "patterns": "stable",
522
+ "patterns.debate": "stable",
523
+ "patterns.plan_and_execute": "stable",
524
+ "patterns.reflective": "stable",
525
+ "patterns.team_lead": "stable",
526
526
  "pending": "beta",
527
527
  "pipeline": "beta",
528
- "policy": "beta",
528
+ "policy": "stable",
529
529
  "pricing": "stable",
530
530
  "prompt": "stable",
531
531
  "providers": "stable",
@@ -641,3 +641,34 @@ class TestSupabaseSessionStoreSearch:
641
641
 
642
642
  results = store.search('"quartz"')
643
643
  assert [r.session_id for r in results] == ["s2"]
644
+
645
+
646
+ def test_search_sends_validated_postgrest_json_filter() -> None:
647
+ """search() filters on the ``memory_json->>messages`` text projection.
648
+
649
+ ``col->>key`` is valid PostgREST syntax (extracts a JSON field as text) —
650
+ confirmed against the Supabase docs (e.g. ``metadata->>stuff`` in a filter).
651
+ A 2026-06-15 audit flagged this as "always returns empty"; that was a false
652
+ positive. This test locks the exact column expression so a refactor can't
653
+ silently send invalid syntax (which WOULD make server-side search empty),
654
+ and asserts the term is JSON-escaped to match the escaped jsonb projection.
655
+ """
656
+ recorded: list = []
657
+
658
+ class _RecordingBuilder(FakeQueryBuilder):
659
+ def ilike(self, col: str, pattern: str) -> "FakeQueryBuilder":
660
+ recorded.append((col, pattern))
661
+ return super().ilike(col, pattern)
662
+
663
+ class _RecordingClient(FakeSupabaseClient):
664
+ def table(self, name: str) -> "FakeQueryBuilder":
665
+ return _RecordingBuilder(self._data, name, "select")
666
+
667
+ store = _make_store(_RecordingClient())
668
+ store.save("s1", _search_memory("quartz crystal"))
669
+ store.search("quartz")
670
+
671
+ assert recorded, "search() issued no ilike filter"
672
+ assert {col for col, _ in recorded} == {"memory_json->>messages"}
673
+ # The pattern is wrapped in % and lower-cased per term.
674
+ assert all(p.startswith("%") and p.endswith("%") for _, p in recorded)
File without changes
File without changes