selectools 0.23.0__tar.gz → 0.24.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 (300) hide show
  1. {selectools-0.23.0/src/selectools.egg-info → selectools-0.24.0}/PKG-INFO +59 -8
  2. {selectools-0.23.0 → selectools-0.24.0}/README.md +51 -7
  3. {selectools-0.23.0 → selectools-0.24.0}/pyproject.toml +10 -1
  4. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/__init__.py +67 -1
  5. selectools-0.24.0/src/selectools/a2a/__init__.py +54 -0
  6. selectools-0.24.0/src/selectools/a2a/client.py +174 -0
  7. selectools-0.24.0/src/selectools/a2a/server.py +406 -0
  8. selectools-0.24.0/src/selectools/a2a/types.py +169 -0
  9. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/_tool_executor.py +13 -2
  10. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/core.py +9 -0
  11. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/entity_memory.py +4 -0
  12. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/knowledge.py +174 -2
  13. selectools-0.24.0/src/selectools/knowledge_backends.py +220 -0
  14. selectools-0.24.0/src/selectools/pending.py +1123 -0
  15. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/__init__.py +5 -0
  16. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/anthropic_provider.py +70 -8
  17. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/gemini_provider.py +105 -14
  18. selectools-0.24.0/src/selectools/providers/litellm_provider.py +192 -0
  19. selectools-0.24.0/src/selectools/providers/router.py +610 -0
  20. selectools-0.24.0/src/selectools/results.py +224 -0
  21. selectools-0.24.0/src/selectools/serve/__init__.py +54 -0
  22. selectools-0.24.0/src/selectools/serve/api.py +552 -0
  23. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/cli.py +34 -0
  24. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/sessions.py +512 -3
  25. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/__init__.py +75 -1
  26. selectools-0.24.0/src/selectools/toolbox/calculator_tools.py +332 -0
  27. selectools-0.24.0/src/selectools/toolbox/email_tools.py +245 -0
  28. selectools-0.24.0/src/selectools/toolbox/linear_tools.py +286 -0
  29. selectools-0.24.0/src/selectools/toolbox/notion_tools.py +259 -0
  30. selectools-0.24.0/src/selectools/toolbox/pdf_tools.py +155 -0
  31. selectools-0.24.0/src/selectools/toolbox/slack_tools.py +201 -0
  32. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/tools/base.py +8 -0
  33. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/types.py +3 -0
  34. selectools-0.24.0/src/selectools/unified_memory.py +926 -0
  35. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/usage.py +8 -0
  36. {selectools-0.23.0 → selectools-0.24.0/src/selectools.egg-info}/PKG-INFO +59 -8
  37. {selectools-0.23.0 → selectools-0.24.0}/src/selectools.egg-info/SOURCES.txt +25 -0
  38. {selectools-0.23.0 → selectools-0.24.0}/src/selectools.egg-info/requires.txt +9 -0
  39. selectools-0.24.0/tests/test_a2a.py +455 -0
  40. selectools-0.24.0/tests/test_agent_api.py +430 -0
  41. {selectools-0.23.0 → selectools-0.24.0}/tests/test_entity_memory.py +9 -0
  42. selectools-0.24.0/tests/test_knowledge_backend.py +255 -0
  43. selectools-0.24.0/tests/test_knowledge_backend_redis.py +171 -0
  44. selectools-0.24.0/tests/test_knowledge_backend_supabase.py +231 -0
  45. selectools-0.24.0/tests/test_pending.py +1024 -0
  46. selectools-0.24.0/tests/test_results.py +366 -0
  47. {selectools-0.23.0 → selectools-0.24.0}/tests/test_serve_cli.py +39 -0
  48. {selectools-0.23.0 → selectools-0.24.0}/tests/test_sessions.py +334 -0
  49. {selectools-0.23.0 → selectools-0.24.0}/tests/test_sessions_redis.py +68 -0
  50. {selectools-0.23.0 → selectools-0.24.0}/tests/test_sessions_supabase.py +114 -4
  51. selectools-0.24.0/tests/test_unified_memory.py +427 -0
  52. selectools-0.23.0/src/selectools/serve/__init__.py +0 -24
  53. {selectools-0.23.0 → selectools-0.24.0}/LICENSE +0 -0
  54. {selectools-0.23.0 → selectools-0.24.0}/setup.cfg +0 -0
  55. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/_async_utils.py +0 -0
  56. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/__init__.py +0 -0
  57. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/_lifecycle.py +0 -0
  58. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/_memory_manager.py +0 -0
  59. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/_provider_caller.py +0 -0
  60. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/config.py +0 -0
  61. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/agent/config_groups.py +0 -0
  62. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/analytics.py +0 -0
  63. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/audit.py +0 -0
  64. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/cache.py +0 -0
  65. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/cache_redis.py +0 -0
  66. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/cache_semantic.py +0 -0
  67. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/cancellation.py +0 -0
  68. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/checkpoint_postgres.py +0 -0
  69. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/coherence.py +0 -0
  70. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/compose.py +0 -0
  71. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/__init__.py +0 -0
  72. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/anthropic.py +0 -0
  73. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/cohere.py +0 -0
  74. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/gemini.py +0 -0
  75. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/openai.py +0 -0
  76. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/embeddings/provider.py +0 -0
  77. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/env.py +0 -0
  78. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/__init__.py +0 -0
  79. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/__main__.py +0 -0
  80. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/badge.py +0 -0
  81. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/dataset.py +0 -0
  82. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/evaluators.py +0 -0
  83. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/generator.py +0 -0
  84. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/history.py +0 -0
  85. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/html.py +0 -0
  86. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/junit.py +0 -0
  87. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/llm_evaluators.py +0 -0
  88. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/pairwise.py +0 -0
  89. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/regression.py +0 -0
  90. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/report.py +0 -0
  91. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/serve.py +0 -0
  92. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/snapshot.py +0 -0
  93. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/suite.py +0 -0
  94. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/templates.py +0 -0
  95. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/evals/types.py +0 -0
  96. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/exceptions.py +0 -0
  97. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/__init__.py +0 -0
  98. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/base.py +0 -0
  99. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/format.py +0 -0
  100. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/length.py +0 -0
  101. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/pii.py +0 -0
  102. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/pipeline.py +0 -0
  103. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/topic.py +0 -0
  104. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/guardrails/toxicity.py +0 -0
  105. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/knowledge_graph.py +0 -0
  106. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/knowledge_store_redis.py +0 -0
  107. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/knowledge_store_supabase.py +0 -0
  108. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/loop_detection.py +0 -0
  109. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/__init__.py +0 -0
  110. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/_loop.py +0 -0
  111. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/bridge.py +0 -0
  112. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/client.py +0 -0
  113. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/config.py +0 -0
  114. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/multi.py +0 -0
  115. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/mcp/server.py +0 -0
  116. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/memory.py +0 -0
  117. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/models.py +0 -0
  118. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/observe/__init__.py +0 -0
  119. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/observe/langfuse.py +0 -0
  120. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/observe/otel.py +0 -0
  121. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/observe/trace_store.py +0 -0
  122. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/observer.py +0 -0
  123. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/__init__.py +0 -0
  124. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/checkpoint.py +0 -0
  125. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/graph.py +0 -0
  126. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/node.py +0 -0
  127. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/state.py +0 -0
  128. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/orchestration/supervisor.py +0 -0
  129. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/parser.py +0 -0
  130. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/patterns/__init__.py +0 -0
  131. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/patterns/debate.py +0 -0
  132. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/patterns/plan_and_execute.py +0 -0
  133. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/patterns/reflective.py +0 -0
  134. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/patterns/team_lead.py +0 -0
  135. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/pipeline.py +0 -0
  136. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/policy.py +0 -0
  137. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/pricing.py +0 -0
  138. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/prompt.py +0 -0
  139. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/_openai_compat.py +0 -0
  140. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/azure_openai_provider.py +0 -0
  141. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/base.py +0 -0
  142. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/fallback.py +0 -0
  143. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/ollama_provider.py +0 -0
  144. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/openai_provider.py +0 -0
  145. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/providers/stubs.py +0 -0
  146. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/__init__.py +0 -0
  147. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/bm25.py +0 -0
  148. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/chunking.py +0 -0
  149. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/hybrid.py +0 -0
  150. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/loaders.py +0 -0
  151. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/reranker.py +0 -0
  152. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/__init__.py +0 -0
  153. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/chroma.py +0 -0
  154. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/faiss.py +0 -0
  155. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/memory.py +0 -0
  156. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/pgvector.py +0 -0
  157. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/pinecone.py +0 -0
  158. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/qdrant.py +0 -0
  159. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/stores/sqlite.py +0 -0
  160. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/tools.py +0 -0
  161. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/rag/vector_store.py +0 -0
  162. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/security.py +0 -0
  163. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/_starlette_app.py +0 -0
  164. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/_static/builder.css +0 -0
  165. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/_static/builder.html +0 -0
  166. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/_static/builder.js +0 -0
  167. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/app.py +0 -0
  168. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/builder.py +0 -0
  169. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/models.py +0 -0
  170. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/serve/playground.py +0 -0
  171. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/stability.py +0 -0
  172. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/structured.py +0 -0
  173. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/__init__.py +0 -0
  174. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/code_reviewer.py +0 -0
  175. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/customer_support.py +0 -0
  176. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/data_analyst.py +0 -0
  177. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/rag_chatbot.py +0 -0
  178. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/templates/research_assistant.py +0 -0
  179. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/token_estimation.py +0 -0
  180. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/code_tools.py +0 -0
  181. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/data_tools.py +0 -0
  182. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/datetime_tools.py +0 -0
  183. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/db_tools.py +0 -0
  184. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/file_tools.py +0 -0
  185. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/github_tools.py +0 -0
  186. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/memory_tools.py +0 -0
  187. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/search_tools.py +0 -0
  188. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/text_tools.py +0 -0
  189. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/toolbox/web_tools.py +0 -0
  190. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/tools/__init__.py +0 -0
  191. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/tools/decorators.py +0 -0
  192. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/tools/loader.py +0 -0
  193. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/tools/registry.py +0 -0
  194. {selectools-0.23.0 → selectools-0.24.0}/src/selectools/trace.py +0 -0
  195. {selectools-0.23.0 → selectools-0.24.0}/src/selectools.egg-info/dependency_links.txt +0 -0
  196. {selectools-0.23.0 → selectools-0.24.0}/src/selectools.egg-info/entry_points.txt +0 -0
  197. {selectools-0.23.0 → selectools-0.24.0}/src/selectools.egg-info/top_level.txt +0 -0
  198. {selectools-0.23.0 → selectools-0.24.0}/tests/test_approval_gate.py +0 -0
  199. {selectools-0.23.0 → selectools-0.24.0}/tests/test_architecture.py +0 -0
  200. {selectools-0.23.0 → selectools-0.24.0}/tests/test_async_observers.py +0 -0
  201. {selectools-0.23.0 → selectools-0.24.0}/tests/test_audit.py +0 -0
  202. {selectools-0.23.0 → selectools-0.24.0}/tests/test_budget.py +0 -0
  203. {selectools-0.23.0 → selectools-0.24.0}/tests/test_bug_hunt_batch1_core.py +0 -0
  204. {selectools-0.23.0 → selectools-0.24.0}/tests/test_bug_hunt_batch1_security.py +0 -0
  205. {selectools-0.23.0 → selectools-0.24.0}/tests/test_bug_hunt_batch1_tools.py +0 -0
  206. {selectools-0.23.0 → selectools-0.24.0}/tests/test_bug_hunt_regression.py +0 -0
  207. {selectools-0.23.0 → selectools-0.24.0}/tests/test_cache.py +0 -0
  208. {selectools-0.23.0 → selectools-0.24.0}/tests/test_cache_redis.py +0 -0
  209. {selectools-0.23.0 → selectools-0.24.0}/tests/test_cancellation.py +0 -0
  210. {selectools-0.23.0 → selectools-0.24.0}/tests/test_checkpoint_postgres.py +0 -0
  211. {selectools-0.23.0 → selectools-0.24.0}/tests/test_coherence.py +0 -0
  212. {selectools-0.23.0 → selectools-0.24.0}/tests/test_concurrency_smoke.py +0 -0
  213. {selectools-0.23.0 → selectools-0.24.0}/tests/test_consolidation_regression.py +0 -0
  214. {selectools-0.23.0 → selectools-0.24.0}/tests/test_conversation_branching.py +0 -0
  215. {selectools-0.23.0 → selectools-0.24.0}/tests/test_coverage_orchestration.py +0 -0
  216. {selectools-0.23.0 → selectools-0.24.0}/tests/test_document_loaders_extended.py +0 -0
  217. {selectools-0.23.0 → selectools-0.24.0}/tests/test_e2e_langfuse_observer.py +0 -0
  218. {selectools-0.23.0 → selectools-0.24.0}/tests/test_e2e_multimodal.py +0 -0
  219. {selectools-0.23.0 → selectools-0.24.0}/tests/test_e2e_otel_observer.py +0 -0
  220. {selectools-0.23.0 → selectools-0.24.0}/tests/test_e2e_v0_21_0_apps.py +0 -0
  221. {selectools-0.23.0 → selectools-0.24.0}/tests/test_e2e_v0_21_0_simulations.py +0 -0
  222. {selectools-0.23.0 → selectools-0.24.0}/tests/test_env.py +0 -0
  223. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals.py +0 -0
  224. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_advanced.py +0 -0
  225. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_cli.py +0 -0
  226. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_e2e.py +0 -0
  227. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_final.py +0 -0
  228. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_hardening.py +0 -0
  229. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_html_report.py +0 -0
  230. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_new_evaluators.py +0 -0
  231. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_ralph_bugs.py +0 -0
  232. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_release.py +0 -0
  233. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_serve.py +0 -0
  234. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_v017_features.py +0 -0
  235. {selectools-0.23.0 → selectools-0.24.0}/tests/test_evals_v0191.py +0 -0
  236. {selectools-0.23.0 → selectools-0.24.0}/tests/test_features_in_graph.py +0 -0
  237. {selectools-0.23.0 → selectools-0.24.0}/tests/test_final_coverage_a.py +0 -0
  238. {selectools-0.23.0 → selectools-0.24.0}/tests/test_final_coverage_b.py +0 -0
  239. {selectools-0.23.0 → selectools-0.24.0}/tests/test_guardrails.py +0 -0
  240. {selectools-0.23.0 → selectools-0.24.0}/tests/test_hardening.py +0 -0
  241. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge.py +0 -0
  242. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge_graph.py +0 -0
  243. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge_store_redis.py +0 -0
  244. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge_store_supabase.py +0 -0
  245. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge_stores.py +0 -0
  246. {selectools-0.23.0 → selectools-0.24.0}/tests/test_knowledge_stores_error_handling.py +0 -0
  247. {selectools-0.23.0 → selectools-0.24.0}/tests/test_langfuse_observer.py +0 -0
  248. {selectools-0.23.0 → selectools-0.24.0}/tests/test_loop_detection.py +0 -0
  249. {selectools-0.23.0 → selectools-0.24.0}/tests/test_mcp.py +0 -0
  250. {selectools-0.23.0 → selectools-0.24.0}/tests/test_mcp_coverage.py +0 -0
  251. {selectools-0.23.0 → selectools-0.24.0}/tests/test_memory.py +0 -0
  252. {selectools-0.23.0 → selectools-0.24.0}/tests/test_memory_async.py +0 -0
  253. {selectools-0.23.0 → selectools-0.24.0}/tests/test_memory_boundary.py +0 -0
  254. {selectools-0.23.0 → selectools-0.24.0}/tests/test_memory_integration.py +0 -0
  255. {selectools-0.23.0 → selectools-0.24.0}/tests/test_model_switching.py +0 -0
  256. {selectools-0.23.0 → selectools-0.24.0}/tests/test_multi_agent_edge_cases.py +0 -0
  257. {selectools-0.23.0 → selectools-0.24.0}/tests/test_multimodal.py +0 -0
  258. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_checkpoint.py +0 -0
  259. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_e2e.py +0 -0
  260. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_evals.py +0 -0
  261. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_graph.py +0 -0
  262. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_integration.py +0 -0
  263. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_primitives.py +0 -0
  264. {selectools-0.23.0 → selectools-0.24.0}/tests/test_orchestration_supervisor.py +0 -0
  265. {selectools-0.23.0 → selectools-0.24.0}/tests/test_otel_observer.py +0 -0
  266. {selectools-0.23.0 → selectools-0.24.0}/tests/test_parser.py +0 -0
  267. {selectools-0.23.0 → selectools-0.24.0}/tests/test_patterns.py +0 -0
  268. {selectools-0.23.0 → selectools-0.24.0}/tests/test_phase1_design_patterns.py +0 -0
  269. {selectools-0.23.0 → selectools-0.24.0}/tests/test_pipeline.py +0 -0
  270. {selectools-0.23.0 → selectools-0.24.0}/tests/test_pipeline_coverage.py +0 -0
  271. {selectools-0.23.0 → selectools-0.24.0}/tests/test_policy.py +0 -0
  272. {selectools-0.23.0 → selectools-0.24.0}/tests/test_prompt.py +0 -0
  273. {selectools-0.23.0 → selectools-0.24.0}/tests/test_prompt_compression.py +0 -0
  274. {selectools-0.23.0 → selectools-0.24.0}/tests/test_property_based.py +0 -0
  275. {selectools-0.23.0 → selectools-0.24.0}/tests/test_reasoning_strategy.py +0 -0
  276. {selectools-0.23.0 → selectools-0.24.0}/tests/test_remaining_coverage.py +0 -0
  277. {selectools-0.23.0 → selectools-0.24.0}/tests/test_routing_mode.py +0 -0
  278. {selectools-0.23.0 → selectools-0.24.0}/tests/test_security.py +0 -0
  279. {selectools-0.23.0 → selectools-0.24.0}/tests/test_semantic_cache.py +0 -0
  280. {selectools-0.23.0 → selectools-0.24.0}/tests/test_serve_app_coverage.py +0 -0
  281. {selectools-0.23.0 → selectools-0.24.0}/tests/test_sessions_edge_cases.py +0 -0
  282. {selectools-0.23.0 → selectools-0.24.0}/tests/test_simple_observer.py +0 -0
  283. {selectools-0.23.0 → selectools-0.24.0}/tests/test_simulation_evals.py +0 -0
  284. {selectools-0.23.0 → selectools-0.24.0}/tests/test_stability.py +0 -0
  285. {selectools-0.23.0 → selectools-0.24.0}/tests/test_starlette_app.py +0 -0
  286. {selectools-0.23.0 → selectools-0.24.0}/tests/test_structured.py +0 -0
  287. {selectools-0.23.0 → selectools-0.24.0}/tests/test_structured_config.py +0 -0
  288. {selectools-0.23.0 → selectools-0.24.0}/tests/test_structured_tool_results.py +0 -0
  289. {selectools-0.23.0 → selectools-0.24.0}/tests/test_summarize_on_trim.py +0 -0
  290. {selectools-0.23.0 → selectools-0.24.0}/tests/test_templates_coverage.py +0 -0
  291. {selectools-0.23.0 → selectools-0.24.0}/tests/test_terminal_actions.py +0 -0
  292. {selectools-0.23.0 → selectools-0.24.0}/tests/test_token_estimation.py +0 -0
  293. {selectools-0.23.0 → selectools-0.24.0}/tests/test_tool_caching.py +0 -0
  294. {selectools-0.23.0 → selectools-0.24.0}/tests/test_trace.py +0 -0
  295. {selectools-0.23.0 → selectools-0.24.0}/tests/test_trace_html.py +0 -0
  296. {selectools-0.23.0 → selectools-0.24.0}/tests/test_trace_store.py +0 -0
  297. {selectools-0.23.0 → selectools-0.24.0}/tests/test_v016_regression.py +0 -0
  298. {selectools-0.23.0 → selectools-0.24.0}/tests/test_v019_features.py +0 -0
  299. {selectools-0.23.0 → selectools-0.24.0}/tests/test_visual_builder.py +0 -0
  300. {selectools-0.23.0 → selectools-0.24.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.23.0
3
+ Version: 0.24.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>
@@ -55,10 +55,16 @@ Requires-Dist: beautifulsoup4>=4.12.0; extra == "rag"
55
55
  Provides-Extra: observe
56
56
  Requires-Dist: opentelemetry-api>=1.20.0; extra == "observe"
57
57
  Requires-Dist: langfuse>=2.0.0; extra == "observe"
58
+ Provides-Extra: toolbox
59
+ Requires-Dist: requests>=2.28.0; extra == "toolbox"
60
+ Requires-Dist: slack-sdk>=3.27.0; extra == "toolbox"
61
+ Requires-Dist: pdfplumber>=0.11.0; extra == "toolbox"
58
62
  Provides-Extra: evals
59
63
  Requires-Dist: pyyaml>=6.0.0; extra == "evals"
60
64
  Provides-Extra: mcp
61
65
  Requires-Dist: mcp<2.0.0,>=1.0.0; extra == "mcp"
66
+ Provides-Extra: litellm
67
+ Requires-Dist: litellm>=1.0.0; extra == "litellm"
62
68
  Provides-Extra: postgres
63
69
  Requires-Dist: psycopg2-binary>=2.9.0; extra == "postgres"
64
70
  Provides-Extra: supabase
@@ -67,6 +73,7 @@ Provides-Extra: serve
67
73
  Requires-Dist: pyyaml>=6.0.0; extra == "serve"
68
74
  Requires-Dist: starlette>=0.27.0; extra == "serve"
69
75
  Requires-Dist: uvicorn[standard]>=0.24.0; extra == "serve"
76
+ Requires-Dist: httpx>=0.24.0; extra == "serve"
70
77
  Dynamic: license-file
71
78
 
72
79
  ```
@@ -101,6 +108,33 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
101
108
  # selectools serve agent.yaml
102
109
  ```
103
110
 
111
+ ## What's New in v0.24
112
+
113
+ ### v0.24.0 — Production Interop
114
+
115
+ Twelve features focused on running agents in production and connecting them to everything else: serve agents as REST APIs, talk to other agents over A2A, reach 100+ models through LiteLLM, route by cost, and persist memory anywhere.
116
+
117
+ - **Agent-as-API** — `selectools.serve.AgentAPI` turns any Agent (or list of agents) into a production Starlette ASGI app: `POST /v1/chat`, SSE streaming, session CRUD, bearer auth, per-user session isolation. CLI: `selectools serve agent.yaml --api --port 8000`.
118
+ - **A2A protocol** — `A2AServer` + `A2AClient` for agent-to-agent communication: Agent Card discovery (`/.well-known/agent.json`) and JSON-RPC 2.0 `message/send`/`tasks/get`/`tasks/cancel`.
119
+ - **LiteLLMProvider** — instant access to 100+ models (DeepSeek, Groq, Bedrock, ...) via `pip install selectools[litellm]`.
120
+ - **RouterProvider** — cost-optimized routing across model tiers with a deterministic complexity classifier and failure escalation.
121
+ - **Anthropic prompt caching** — opt-in `cache_system=True` / `cache_tools=True` with cache hit-rate fields on `UsageStats`.
122
+ - **UnifiedMemory** — tiered memory orchestrating conversation, knowledge, entity, and the new episodic tier, with token-aware compaction and federated `recall()`.
123
+ - **Cross-session search** — `store.search(query)` on all four SessionStore backends (FTS5-accelerated on SQLite).
124
+ - **KnowledgeBackend** — Supabase/Redis blob persistence for `KnowledgeMemory` on ephemeral infrastructure (Railway, Lambda, Cloud Run).
125
+ - **ToolResult + Artifact** — typed tool results with a `kind` discriminator, plus an `emit_artifact()` side-channel surfaced on `AgentResult.artifacts`.
126
+ - **Deferred confirmation flow** — `selectools.pending` for chat-channel destructive tools where the user's "yes" arrives as a separate webhook turn.
127
+ - **Toolbox expansion** — 15 new tools (33 → 48): safe calculator, email, PDF extraction, Slack, Notion, Linear.
128
+ - **Gemini schema sanitization** — bare `list` and `Dict[K, V]` tool parameters no longer 400 on the Gemini API; loud warnings for flash-lite's silent-empty-response failure mode.
129
+
130
+ ```python
131
+ from selectools.serve import AgentAPI
132
+
133
+ api = AgentAPI(agent, auth_key="secret") # ASGI app: uvicorn main:api
134
+ ```
135
+
136
+ See `CHANGELOG.md` for the full entry (5,968 tests, 106 examples).
137
+
104
138
  ## What's New in v0.23
105
139
 
106
140
  ### v0.23.0 — Supabase Sessions + Builder RAG
@@ -570,7 +604,15 @@ report.to_html("report.html")
570
604
  | **Audit Logging** | JSONL audit trail with privacy controls (redact, hash, omit) and daily rotation. |
571
605
  | **Tool Output Screening** | Prompt injection detection with 15 built-in patterns. Per-tool or global. |
572
606
  | **Coherence Checking** | LLM-based verification that tool calls match user intent — catches injection-driven tool misuse. |
573
- | **Persistent Sessions** | `SessionStore` with JSON file, SQLite, and Redis backends. Auto-save/load with TTL expiry. |
607
+ | **Persistent Sessions** | `SessionStore` with JSON file, SQLite, Redis, and Supabase backends. Auto-save/load with TTL expiry, cross-session `search()`. |
608
+ | **Agent-as-API** | `AgentAPI` serves any agent as a Starlette REST API — chat, SSE streaming, session CRUD, bearer auth, per-user session isolation. |
609
+ | **A2A Protocol** | `A2AServer` + `A2AClient`: Agent Card discovery and JSON-RPC 2.0 messaging between agents. |
610
+ | **LiteLLM Bridge** | `LiteLLMProvider` unlocks 100+ models (DeepSeek, Groq, Bedrock, ...) through one provider class. |
611
+ | **Cost-Based Routing** | `RouterProvider` classifies request complexity and routes to model tiers with automatic failure escalation. |
612
+ | **Unified Memory** | `UnifiedMemory` orchestrates conversation, knowledge, entity, and episodic tiers with token-aware compaction and federated `recall()`. |
613
+ | **Typed Tool Results** | `ToolResult` base with `kind` discriminator; `emit_artifact()` side-channel surfaces files/URLs on `AgentResult.artifacts`. |
614
+ | **Deferred Confirmation** | `selectools.pending` — confirm destructive chat-channel tools across webhook turns with TTL, scope, and args-digest matching. |
615
+ | **Prompt Caching** | Anthropic `cache_system`/`cache_tools` markers with cache hit-rate fields on `UsageStats`. |
574
616
  | **Entity Memory** | LLM-based entity extraction with deduplication, LRU pruning, and system prompt injection. |
575
617
  | **Knowledge Graph** | Relationship triple extraction with in-memory and SQLite storage and keyword-based querying. |
576
618
  | **Cross-Session Knowledge** | Daily logs + persistent facts with auto-registered `remember` tool. |
@@ -585,7 +627,9 @@ report.to_html("report.html")
585
627
 
586
628
  ## What's Included
587
629
 
588
- - **5 LLM Providers**: OpenAI, Azure OpenAI, Anthropic, Gemini, Ollama + FallbackProvider (auto-failover)
630
+ - **6 LLM Providers**: OpenAI, Azure OpenAI, Anthropic, Gemini, Ollama, LiteLLM (100+ models) + FallbackProvider (auto-failover) + RouterProvider (cost-based routing)
631
+ - **Agent-as-API**: `AgentAPI` — production REST endpoints (chat, SSE streaming, sessions) from any agent
632
+ - **A2A Protocol**: Agent Card discovery + JSON-RPC 2.0 agent-to-agent messaging
589
633
  - **Structured Output**: Pydantic / JSON Schema `response_format` with auto-retry
590
634
  - **Execution Traces**: `result.trace` with typed timeline of every agent step
591
635
  - **Reasoning Visibility**: `result.reasoning` explains *why* the agent chose a tool
@@ -598,9 +642,14 @@ report.to_html("report.html")
598
642
  - **Dynamic Tool Loading**: Plugin system with hot-reload support
599
643
  - **Response Caching**: InMemoryCache and RedisCache with stats tracking
600
644
  - **152 Model Registry**: Type-safe constants with pricing and metadata
601
- - **Pre-built Toolbox**: 24 tools for files, data, text, datetime, web
602
- - **Persistent Sessions**: 3 backends (JSON file, SQLite, Redis) with TTL
645
+ - **Pre-built Toolbox**: 48 tools for files, data, text, datetime, web, code, search, GitHub, DB, calculator, email, PDF, Slack, Notion, Linear
646
+ - **Persistent Sessions**: 4 backends (JSON file, SQLite, Redis, Supabase) with TTL and cross-session search
603
647
  - **Entity Memory**: LLM-based named entity extraction and tracking
648
+ - **Unified Memory**: tiered conversation/knowledge/entity/episodic memory with token-aware compaction
649
+ - **Knowledge Backends**: Supabase/Redis blob persistence for KnowledgeMemory on ephemeral infra
650
+ - **Typed Tool Results**: `ToolResult` base class + `Artifact` side-channel via `emit_artifact()`
651
+ - **Deferred Confirmation**: `selectools.pending` for chat-channel destructive-tool confirmation
652
+ - **Anthropic Prompt Caching**: `cache_system`/`cache_tools` with hit-rate visibility on `UsageStats`
604
653
  - **Knowledge Graph**: Triple extraction with in-memory and SQLite storage
605
654
  - **Cross-Session Knowledge**: Daily logs + persistent memory with `remember` tool, pluggable stores (File, SQLite), importance scoring, TTL
606
655
  - **Token Budget & Cancellation**: `max_total_tokens`, `max_cost_usd` hard limits; `CancellationToken` for cooperative stopping
@@ -611,10 +660,10 @@ report.to_html("report.html")
611
660
  - **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
612
661
  - **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
613
662
  - **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
614
- - **96 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions (incl. Supabase), entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
663
+ - **106 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions (incl. Supabase), entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, agent-as-API, A2A, routing, unified memory, and more
615
664
  - **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
616
665
  - **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
617
- - **5332 Tests**: Unit, integration, regression, and E2E with real API calls
666
+ - **5968 Tests**: Unit, integration, regression, and E2E with real API calls
618
667
 
619
668
  ## Install
620
669
 
@@ -960,6 +1009,8 @@ See [docs/modules/STREAMING.md](https://github.com/johnnichev/selectools/blob/ma
960
1009
  | **Anthropic** | Yes | Yes | Yes | Paid |
961
1010
  | **Gemini** | Yes | Yes | Yes | Free tier |
962
1011
  | **Ollama** | Yes | No | No | Free (local) |
1012
+ | **LiteLLM** | Yes | Yes | Yes | Varies (100+ models) |
1013
+ | **Router** | Yes | Yes | Yes | Varies (cost-routes tiers) |
963
1014
  | **Fallback** | Yes | Yes | Yes | Varies (wraps others) |
964
1015
  | **Local** | No | No | No | Free (testing) |
965
1016
 
@@ -1238,7 +1289,7 @@ pytest tests/ -x -q # All tests
1238
1289
  pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
1239
1290
  ```
1240
1291
 
1241
- 5332 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.
1292
+ 5968 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, serve API, A2A, routing, and E2E integration with real API calls.
1242
1293
 
1243
1294
  ## License
1244
1295
 
@@ -30,6 +30,33 @@ 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.24
34
+
35
+ ### v0.24.0 — Production Interop
36
+
37
+ Twelve features focused on running agents in production and connecting them to everything else: serve agents as REST APIs, talk to other agents over A2A, reach 100+ models through LiteLLM, route by cost, and persist memory anywhere.
38
+
39
+ - **Agent-as-API** — `selectools.serve.AgentAPI` turns any Agent (or list of agents) into a production Starlette ASGI app: `POST /v1/chat`, SSE streaming, session CRUD, bearer auth, per-user session isolation. CLI: `selectools serve agent.yaml --api --port 8000`.
40
+ - **A2A protocol** — `A2AServer` + `A2AClient` for agent-to-agent communication: Agent Card discovery (`/.well-known/agent.json`) and JSON-RPC 2.0 `message/send`/`tasks/get`/`tasks/cancel`.
41
+ - **LiteLLMProvider** — instant access to 100+ models (DeepSeek, Groq, Bedrock, ...) via `pip install selectools[litellm]`.
42
+ - **RouterProvider** — cost-optimized routing across model tiers with a deterministic complexity classifier and failure escalation.
43
+ - **Anthropic prompt caching** — opt-in `cache_system=True` / `cache_tools=True` with cache hit-rate fields on `UsageStats`.
44
+ - **UnifiedMemory** — tiered memory orchestrating conversation, knowledge, entity, and the new episodic tier, with token-aware compaction and federated `recall()`.
45
+ - **Cross-session search** — `store.search(query)` on all four SessionStore backends (FTS5-accelerated on SQLite).
46
+ - **KnowledgeBackend** — Supabase/Redis blob persistence for `KnowledgeMemory` on ephemeral infrastructure (Railway, Lambda, Cloud Run).
47
+ - **ToolResult + Artifact** — typed tool results with a `kind` discriminator, plus an `emit_artifact()` side-channel surfaced on `AgentResult.artifacts`.
48
+ - **Deferred confirmation flow** — `selectools.pending` for chat-channel destructive tools where the user's "yes" arrives as a separate webhook turn.
49
+ - **Toolbox expansion** — 15 new tools (33 → 48): safe calculator, email, PDF extraction, Slack, Notion, Linear.
50
+ - **Gemini schema sanitization** — bare `list` and `Dict[K, V]` tool parameters no longer 400 on the Gemini API; loud warnings for flash-lite's silent-empty-response failure mode.
51
+
52
+ ```python
53
+ from selectools.serve import AgentAPI
54
+
55
+ api = AgentAPI(agent, auth_key="secret") # ASGI app: uvicorn main:api
56
+ ```
57
+
58
+ See `CHANGELOG.md` for the full entry (5,968 tests, 106 examples).
59
+
33
60
  ## What's New in v0.23
34
61
 
35
62
  ### v0.23.0 — Supabase Sessions + Builder RAG
@@ -499,7 +526,15 @@ report.to_html("report.html")
499
526
  | **Audit Logging** | JSONL audit trail with privacy controls (redact, hash, omit) and daily rotation. |
500
527
  | **Tool Output Screening** | Prompt injection detection with 15 built-in patterns. Per-tool or global. |
501
528
  | **Coherence Checking** | LLM-based verification that tool calls match user intent — catches injection-driven tool misuse. |
502
- | **Persistent Sessions** | `SessionStore` with JSON file, SQLite, and Redis backends. Auto-save/load with TTL expiry. |
529
+ | **Persistent Sessions** | `SessionStore` with JSON file, SQLite, Redis, and Supabase backends. Auto-save/load with TTL expiry, cross-session `search()`. |
530
+ | **Agent-as-API** | `AgentAPI` serves any agent as a Starlette REST API — chat, SSE streaming, session CRUD, bearer auth, per-user session isolation. |
531
+ | **A2A Protocol** | `A2AServer` + `A2AClient`: Agent Card discovery and JSON-RPC 2.0 messaging between agents. |
532
+ | **LiteLLM Bridge** | `LiteLLMProvider` unlocks 100+ models (DeepSeek, Groq, Bedrock, ...) through one provider class. |
533
+ | **Cost-Based Routing** | `RouterProvider` classifies request complexity and routes to model tiers with automatic failure escalation. |
534
+ | **Unified Memory** | `UnifiedMemory` orchestrates conversation, knowledge, entity, and episodic tiers with token-aware compaction and federated `recall()`. |
535
+ | **Typed Tool Results** | `ToolResult` base with `kind` discriminator; `emit_artifact()` side-channel surfaces files/URLs on `AgentResult.artifacts`. |
536
+ | **Deferred Confirmation** | `selectools.pending` — confirm destructive chat-channel tools across webhook turns with TTL, scope, and args-digest matching. |
537
+ | **Prompt Caching** | Anthropic `cache_system`/`cache_tools` markers with cache hit-rate fields on `UsageStats`. |
503
538
  | **Entity Memory** | LLM-based entity extraction with deduplication, LRU pruning, and system prompt injection. |
504
539
  | **Knowledge Graph** | Relationship triple extraction with in-memory and SQLite storage and keyword-based querying. |
505
540
  | **Cross-Session Knowledge** | Daily logs + persistent facts with auto-registered `remember` tool. |
@@ -514,7 +549,9 @@ report.to_html("report.html")
514
549
 
515
550
  ## What's Included
516
551
 
517
- - **5 LLM Providers**: OpenAI, Azure OpenAI, Anthropic, Gemini, Ollama + FallbackProvider (auto-failover)
552
+ - **6 LLM Providers**: OpenAI, Azure OpenAI, Anthropic, Gemini, Ollama, LiteLLM (100+ models) + FallbackProvider (auto-failover) + RouterProvider (cost-based routing)
553
+ - **Agent-as-API**: `AgentAPI` — production REST endpoints (chat, SSE streaming, sessions) from any agent
554
+ - **A2A Protocol**: Agent Card discovery + JSON-RPC 2.0 agent-to-agent messaging
518
555
  - **Structured Output**: Pydantic / JSON Schema `response_format` with auto-retry
519
556
  - **Execution Traces**: `result.trace` with typed timeline of every agent step
520
557
  - **Reasoning Visibility**: `result.reasoning` explains *why* the agent chose a tool
@@ -527,9 +564,14 @@ report.to_html("report.html")
527
564
  - **Dynamic Tool Loading**: Plugin system with hot-reload support
528
565
  - **Response Caching**: InMemoryCache and RedisCache with stats tracking
529
566
  - **152 Model Registry**: Type-safe constants with pricing and metadata
530
- - **Pre-built Toolbox**: 24 tools for files, data, text, datetime, web
531
- - **Persistent Sessions**: 3 backends (JSON file, SQLite, Redis) with TTL
567
+ - **Pre-built Toolbox**: 48 tools for files, data, text, datetime, web, code, search, GitHub, DB, calculator, email, PDF, Slack, Notion, Linear
568
+ - **Persistent Sessions**: 4 backends (JSON file, SQLite, Redis, Supabase) with TTL and cross-session search
532
569
  - **Entity Memory**: LLM-based named entity extraction and tracking
570
+ - **Unified Memory**: tiered conversation/knowledge/entity/episodic memory with token-aware compaction
571
+ - **Knowledge Backends**: Supabase/Redis blob persistence for KnowledgeMemory on ephemeral infra
572
+ - **Typed Tool Results**: `ToolResult` base class + `Artifact` side-channel via `emit_artifact()`
573
+ - **Deferred Confirmation**: `selectools.pending` for chat-channel destructive-tool confirmation
574
+ - **Anthropic Prompt Caching**: `cache_system`/`cache_tools` with hit-rate visibility on `UsageStats`
533
575
  - **Knowledge Graph**: Triple extraction with in-memory and SQLite storage
534
576
  - **Cross-Session Knowledge**: Daily logs + persistent memory with `remember` tool, pluggable stores (File, SQLite), importance scoring, TTL
535
577
  - **Token Budget & Cancellation**: `max_total_tokens`, `max_cost_usd` hard limits; `CancellationToken` for cooperative stopping
@@ -540,10 +582,10 @@ report.to_html("report.html")
540
582
  - **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
541
583
  - **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
542
584
  - **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
543
- - **96 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions (incl. Supabase), entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
585
+ - **106 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions (incl. Supabase), entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, agent-as-API, A2A, routing, unified memory, and more
544
586
  - **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
545
587
  - **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
546
- - **5332 Tests**: Unit, integration, regression, and E2E with real API calls
588
+ - **5968 Tests**: Unit, integration, regression, and E2E with real API calls
547
589
 
548
590
  ## Install
549
591
 
@@ -889,6 +931,8 @@ See [docs/modules/STREAMING.md](https://github.com/johnnichev/selectools/blob/ma
889
931
  | **Anthropic** | Yes | Yes | Yes | Paid |
890
932
  | **Gemini** | Yes | Yes | Yes | Free tier |
891
933
  | **Ollama** | Yes | No | No | Free (local) |
934
+ | **LiteLLM** | Yes | Yes | Yes | Varies (100+ models) |
935
+ | **Router** | Yes | Yes | Yes | Varies (cost-routes tiers) |
892
936
  | **Fallback** | Yes | Yes | Yes | Varies (wraps others) |
893
937
  | **Local** | No | No | No | Free (testing) |
894
938
 
@@ -1167,7 +1211,7 @@ pytest tests/ -x -q # All tests
1167
1211
  pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
1168
1212
  ```
1169
1213
 
1170
- 5332 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.
1214
+ 5968 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, serve API, A2A, routing, and E2E integration with real API calls.
1171
1215
 
1172
1216
  ## License
1173
1217
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "selectools"
7
- version = "0.23.0"
7
+ version = "0.24.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"
@@ -75,12 +75,20 @@ observe = [
75
75
  "opentelemetry-api>=1.20.0",
76
76
  "langfuse>=2.0.0",
77
77
  ]
78
+ toolbox = [
79
+ "requests>=2.28.0",
80
+ "slack-sdk>=3.27.0",
81
+ "pdfplumber>=0.11.0",
82
+ ]
78
83
  evals = [
79
84
  "pyyaml>=6.0.0",
80
85
  ]
81
86
  mcp = [
82
87
  "mcp>=1.0.0,<2.0.0",
83
88
  ]
89
+ litellm = [
90
+ "litellm>=1.0.0",
91
+ ]
84
92
  postgres = [
85
93
  "psycopg2-binary>=2.9.0",
86
94
  ]
@@ -91,6 +99,7 @@ serve = [
91
99
  "pyyaml>=6.0.0",
92
100
  "starlette>=0.27.0",
93
101
  "uvicorn[standard]>=0.24.0",
102
+ "httpx>=0.24.0",
94
103
  ]
95
104
 
96
105
  [project.scripts]
@@ -1,6 +1,6 @@
1
1
  """Public exports for the selectools package."""
2
2
 
3
- __version__ = "0.23.0"
3
+ __version__ = "0.24.0"
4
4
 
5
5
  # Import submodules (lazy loading for optional dependencies)
6
6
  from . import embeddings, evals, guardrails, models, observe, patterns, rag, toolbox
@@ -50,11 +50,16 @@ from .guardrails import (
50
50
  )
51
51
  from .knowledge import (
52
52
  FileKnowledgeStore,
53
+ KnowledgeBackend,
53
54
  KnowledgeEntry,
54
55
  KnowledgeMemory,
55
56
  KnowledgeStore,
56
57
  SQLiteKnowledgeStore,
57
58
  )
59
+ from .knowledge_backends import (
60
+ RedisKnowledgeBackend,
61
+ SupabaseKnowledgeBackend,
62
+ )
58
63
  from .knowledge_graph import (
59
64
  InMemoryTripleStore,
60
65
  KnowledgeGraphMemory,
@@ -122,6 +127,20 @@ from .patterns import (
122
127
  TeamLeadAgent,
123
128
  TeamLeadResult,
124
129
  )
130
+ from .pending import (
131
+ ChannelAgent,
132
+ ConfirmOutcome,
133
+ ConfirmParser,
134
+ InMemoryPendingStore,
135
+ PendingAction,
136
+ PendingActionExistsError,
137
+ PendingActionStore,
138
+ PendingConfirmation,
139
+ RedisPendingStore,
140
+ RegexConfirmParser,
141
+ compute_args_digest,
142
+ stash_pending,
143
+ )
125
144
  from .pipeline import Pipeline, Step, StepResult, branch, cache_step, parallel, retry, step
126
145
  from .policy import PolicyDecision, PolicyResult, ToolPolicy
127
146
  from .pricing import PRICING, calculate_cost, calculate_embedding_cost, get_model_pricing
@@ -130,13 +149,16 @@ from .providers.anthropic_provider import AnthropicProvider
130
149
  from .providers.azure_openai_provider import AzureOpenAIProvider
131
150
  from .providers.fallback import FallbackProvider
132
151
  from .providers.gemini_provider import GeminiProvider
152
+ from .providers.litellm_provider import LiteLLMProvider
133
153
  from .providers.ollama_provider import OllamaProvider
134
154
  from .providers.openai_provider import OpenAIProvider
135
155
  from .providers.stubs import LocalProvider
156
+ from .results import Ambiguous, Artifact, NotFound, ToolResult, emit_artifact
136
157
  from .sessions import (
137
158
  JsonFileSessionStore,
138
159
  RedisSessionStore,
139
160
  SessionMetadata,
161
+ SessionSearchResult,
140
162
  SessionStore,
141
163
  SQLiteSessionStore,
142
164
  SupabaseSessionStore,
@@ -147,6 +169,16 @@ from .token_estimation import TokenEstimate, estimate_run_tokens, estimate_token
147
169
  from .tools import Tool, ToolParameter, ToolRegistry, tool
148
170
  from .trace import AgentTrace, StepType, TraceStep, trace_to_html, trace_to_json
149
171
  from .types import AgentResult, ContentPart, Message, Role, ToolCall, image_message, text_content
172
+ from .unified_memory import (
173
+ DEFAULT_IMPORTANCE_RULES,
174
+ Episode,
175
+ EpisodicMemory,
176
+ ImportanceRule,
177
+ InMemoryKnowledgeStore,
178
+ RecallResult,
179
+ UnifiedMemory,
180
+ score_importance,
181
+ )
150
182
  from .usage import AgentUsage, UsageStats
151
183
 
152
184
  __all__ = [
@@ -172,6 +204,7 @@ __all__ = [
172
204
  "AnthropicProvider",
173
205
  "GeminiProvider",
174
206
  "OllamaProvider",
207
+ "LiteLLMProvider",
175
208
  "LocalProvider",
176
209
  "FallbackProvider",
177
210
  "ToolRegistry",
@@ -218,6 +251,25 @@ __all__ = [
218
251
  "PolicyResult",
219
252
  # Structured output
220
253
  "ResponseFormat",
254
+ # Typed tool results + artifact side-channel (issue #59)
255
+ "ToolResult",
256
+ "Ambiguous",
257
+ "NotFound",
258
+ "Artifact",
259
+ "emit_artifact",
260
+ # Deferred confirmation flow (issue #58)
261
+ "PendingAction",
262
+ "PendingActionStore",
263
+ "PendingActionExistsError",
264
+ "InMemoryPendingStore",
265
+ "RedisPendingStore",
266
+ "ConfirmOutcome",
267
+ "ConfirmParser",
268
+ "RegexConfirmParser",
269
+ "PendingConfirmation",
270
+ "ChannelAgent",
271
+ "stash_pending",
272
+ "compute_args_digest",
221
273
  # Stability markers
222
274
  "stable",
223
275
  "beta",
@@ -261,6 +313,7 @@ __all__ = [
261
313
  # Sessions
262
314
  "SessionStore",
263
315
  "SessionMetadata",
316
+ "SessionSearchResult",
264
317
  "JsonFileSessionStore",
265
318
  "SQLiteSessionStore",
266
319
  "RedisSessionStore",
@@ -277,6 +330,10 @@ __all__ = [
277
330
  # Knowledge stores (optional deps: redis, supabase)
278
331
  # from selectools.knowledge_store_redis import RedisKnowledgeStore
279
332
  # from selectools.knowledge_store_supabase import SupabaseKnowledgeStore
333
+ # Knowledge backends (blob persistence between deploys; lazy optional deps)
334
+ "KnowledgeBackend",
335
+ "SupabaseKnowledgeBackend",
336
+ "RedisKnowledgeBackend",
280
337
  # Token estimation
281
338
  "TokenEstimate",
282
339
  "estimate_tokens",
@@ -287,6 +344,15 @@ __all__ = [
287
344
  "InMemoryTripleStore",
288
345
  "SQLiteTripleStore",
289
346
  "KnowledgeGraphMemory",
347
+ # Unified Memory (tiered memory with auto-promotion)
348
+ "UnifiedMemory",
349
+ "EpisodicMemory",
350
+ "Episode",
351
+ "ImportanceRule",
352
+ "InMemoryKnowledgeStore",
353
+ "RecallResult",
354
+ "DEFAULT_IMPORTANCE_RULES",
355
+ "score_importance",
290
356
  # Submodules (for lazy loading)
291
357
  "embeddings",
292
358
  "observe",
@@ -0,0 +1,54 @@
1
+ """
2
+ A2A protocol — agent-to-agent communication (Google-backed standard).
3
+
4
+ Serving::
5
+
6
+ from selectools.serve import A2AServer # or selectools.a2a
7
+
8
+ server = A2AServer(agent=my_agent, auth_token="sk-...")
9
+ server.serve(port=8000)
10
+
11
+ Consuming::
12
+
13
+ from selectools.a2a import A2AClient
14
+
15
+ client = A2AClient("https://other-agent.example.com")
16
+ card = await client.discover() # reads /.well-known/agent.json
17
+ result = await client.send_task("Research quantum computing trends")
18
+
19
+ The server requires ``starlette`` and the client requires ``httpx``
20
+ (both ship with ``pip install selectools[serve]``); imports are lazy so
21
+ this package loads without them.
22
+ """
23
+
24
+ from typing import Any
25
+
26
+ from .types import A2AError, A2ATask, AgentCard, AgentSkill, TaskState
27
+
28
+ __all__ = [
29
+ "A2AClient",
30
+ "A2AError",
31
+ "A2AServer",
32
+ "A2ATask",
33
+ "AgentCard",
34
+ "AgentSkill",
35
+ "TaskState",
36
+ ]
37
+
38
+
39
+ def __getattr__(name: str) -> Any:
40
+ """Lazily import the server (starlette) and client (httpx)."""
41
+ if name == "A2AServer":
42
+ try:
43
+ from .server import A2AServer
44
+ except ImportError as exc:
45
+ raise ImportError(
46
+ "A2AServer requires the 'starlette' package. "
47
+ "Install it with: pip install selectools[serve]"
48
+ ) from exc
49
+ return A2AServer
50
+ if name == "A2AClient":
51
+ from .client import A2AClient
52
+
53
+ return A2AClient
54
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,174 @@
1
+ """
2
+ A2A client — discover and talk to remote A2A agents.
3
+
4
+ Usage::
5
+
6
+ from selectools.a2a import A2AClient
7
+
8
+ client = A2AClient("https://other-agent.example.com")
9
+ card = await client.discover() # reads /.well-known/agent.json
10
+ result = await client.send_task("Research quantum computing trends")
11
+ print(result.text)
12
+
13
+ # Sync code can use the *_sync wrappers:
14
+ card = client.discover_sync()
15
+
16
+ Requires ``httpx`` (ships with ``pip install selectools[serve]``); the
17
+ import is lazy so this module loads without it.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import uuid
23
+ from typing import Any, Dict, List, Optional
24
+
25
+ from .._async_utils import run_sync
26
+ from ..stability import beta
27
+ from .types import A2AError, A2ATask, AgentCard
28
+
29
+ __all__ = ["A2AClient"]
30
+
31
+
32
+ def _httpx() -> Any:
33
+ try:
34
+ import httpx
35
+ except ImportError as exc:
36
+ raise ImportError(
37
+ "A2AClient requires the 'httpx' package. Install it with: pip install selectools[serve]"
38
+ ) from exc
39
+ return httpx
40
+
41
+
42
+ @beta
43
+ class A2AClient:
44
+ """Client for a remote A2A agent (Agent Card discovery + task sending).
45
+
46
+ Args:
47
+ base_url: Root URL of the remote agent, e.g.
48
+ ``"https://other-agent.example.com"``. The Agent Card is read
49
+ from ``{base_url}/.well-known/agent.json`` and tasks are posted
50
+ to ``{base_url}/a2a``.
51
+ auth_token: Optional bearer token sent as
52
+ ``Authorization: Bearer <auth_token>`` on every request.
53
+ timeout: Request timeout in seconds (default 30).
54
+ transport: Optional ``httpx`` transport — pass
55
+ ``httpx.ASGITransport(app=server)`` to talk to an in-process
56
+ :class:`~selectools.a2a.server.A2AServer` without a socket.
57
+
58
+ Raises:
59
+ A2AError: On transport failures (non-2xx responses) and JSON-RPC
60
+ protocol errors. Agent failures are NOT raised — they come back
61
+ as an :class:`A2ATask` with ``state == TaskState.FAILED``.
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ base_url: str,
67
+ auth_token: Optional[str] = None,
68
+ timeout: float = 30.0,
69
+ transport: Optional[Any] = None,
70
+ ) -> None:
71
+ self._base_url = base_url.rstrip("/")
72
+ self._auth_token = auth_token
73
+ self._timeout = timeout
74
+ self._transport = transport
75
+
76
+ def _headers(self) -> Dict[str, str]:
77
+ headers = {"Content-Type": "application/json"}
78
+ if self._auth_token:
79
+ headers["Authorization"] = f"Bearer {self._auth_token}"
80
+ return headers
81
+
82
+ def _async_client(self) -> Any:
83
+ httpx = _httpx()
84
+ kwargs: Dict[str, Any] = {"timeout": self._timeout}
85
+ if self._transport is not None:
86
+ kwargs["transport"] = self._transport
87
+ return httpx.AsyncClient(**kwargs)
88
+
89
+ @staticmethod
90
+ def _check_http(response: Any) -> None:
91
+ if response.status_code >= 400:
92
+ raise A2AError(f"HTTP {response.status_code} from A2A server: {response.text[:500]}")
93
+
94
+ # ── discovery ────────────────────────────────────────────────────────────
95
+
96
+ async def discover(self) -> AgentCard:
97
+ """Fetch and parse the remote Agent Card from /.well-known/agent.json."""
98
+ async with self._async_client() as client:
99
+ response = await client.get(
100
+ f"{self._base_url}/.well-known/agent.json", headers=self._headers()
101
+ )
102
+ self._check_http(response)
103
+ return AgentCard.from_dict(response.json())
104
+
105
+ def discover_sync(self) -> AgentCard:
106
+ """Synchronous wrapper around :meth:`discover`."""
107
+ return run_sync(self.discover())
108
+
109
+ # ── tasks ────────────────────────────────────────────────────────────────
110
+
111
+ async def _call(self, method: str, params: Dict[str, Any]) -> Any:
112
+ """Issue one JSON-RPC call against POST /a2a and return its result."""
113
+ payload = {
114
+ "jsonrpc": "2.0",
115
+ "id": uuid.uuid4().hex,
116
+ "method": method,
117
+ "params": params,
118
+ }
119
+ async with self._async_client() as client:
120
+ response = await client.post(
121
+ f"{self._base_url}/a2a", json=payload, headers=self._headers()
122
+ )
123
+ self._check_http(response)
124
+ body = response.json()
125
+ if "error" in body:
126
+ error = body["error"] or {}
127
+ raise A2AError(
128
+ str(error.get("message", "Unknown A2A error")),
129
+ code=error.get("code"),
130
+ data=error.get("data"),
131
+ )
132
+ return body.get("result")
133
+
134
+ async def send_task(
135
+ self,
136
+ text: str,
137
+ context_id: Optional[str] = None,
138
+ extra_parts: Optional[List[Dict[str, Any]]] = None,
139
+ ) -> A2ATask:
140
+ """Send a text task via ``message/send`` and return the final task.
141
+
142
+ Args:
143
+ text: The task prompt (becomes a part of kind ``"text"``).
144
+ context_id: Optional conversation context id to group tasks.
145
+ extra_parts: Optional additional A2A parts (``file``/``data``)
146
+ appended after the text part. The v1 server is text-first.
147
+ """
148
+ parts: List[Dict[str, Any]] = [{"kind": "text", "text": text}]
149
+ if extra_parts:
150
+ parts.extend(extra_parts)
151
+ message: Dict[str, Any] = {
152
+ "role": "user",
153
+ "parts": parts,
154
+ "messageId": uuid.uuid4().hex,
155
+ "kind": "message",
156
+ }
157
+ if context_id:
158
+ message["contextId"] = context_id
159
+ result = await self._call("message/send", {"message": message})
160
+ return A2ATask.from_dict(result or {})
161
+
162
+ def send_task_sync(
163
+ self,
164
+ text: str,
165
+ context_id: Optional[str] = None,
166
+ extra_parts: Optional[List[Dict[str, Any]]] = None,
167
+ ) -> A2ATask:
168
+ """Synchronous wrapper around :meth:`send_task`."""
169
+ return run_sync(self.send_task(text, context_id=context_id, extra_parts=extra_parts))
170
+
171
+ async def get_task(self, task_id: str) -> A2ATask:
172
+ """Fetch a previously created task via ``tasks/get``."""
173
+ result = await self._call("tasks/get", {"id": task_id})
174
+ return A2ATask.from_dict(result or {})