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.
- {selectools-0.28.0/src/selectools.egg-info → selectools-0.29.0}/PKG-INFO +14 -1
- {selectools-0.28.0 → selectools-0.29.0}/README.md +13 -0
- {selectools-0.28.0 → selectools-0.29.0}/pyproject.toml +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/__init__.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/config.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/__init__.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/checkpoint.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/graph.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/node.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/state.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/orchestration/supervisor.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/__init__.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/debate.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/plan_and_execute.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/reflective.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/patterns/team_lead.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/policy.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/sessions.py +1 -1
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/calculator_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/code_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/db_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/email_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/github_tools.py +4 -4
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/linear_tools.py +4 -4
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/notion_tools.py +4 -4
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/pdf_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/search_tools.py +3 -3
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/slack_tools.py +4 -4
- {selectools-0.28.0 → selectools-0.29.0/src/selectools.egg-info}/PKG-INFO +14 -1
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_architecture.py +12 -12
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_supabase.py +31 -0
- {selectools-0.28.0 → selectools-0.29.0}/LICENSE +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/setup.cfg +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_async_utils.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_json_utils.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/_ssrf.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/client.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/server.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/a2a/types.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_lifecycle.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_memory_manager.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_planning.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_provider_caller.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/_tool_executor.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/config_groups.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/agent/core.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/analytics.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/audit.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cache_semantic.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/cancellation.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/checkpoint_postgres.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/coherence.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/compose.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/anthropic.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/cohere.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/gemini.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/openai.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/embeddings/provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/entity_memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/env.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/__main__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/badge.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/dataset.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/evaluators.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/generator.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/history.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/html.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/junit.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/llm_evaluators.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/pairwise.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/regression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/report.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/serve.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/snapshot.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/suite.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/templates.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/evals/types.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/exceptions.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/base.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/format.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/injection.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/length.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/pii.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/pipeline.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/topic.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/guardrails/toxicity.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_backends.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_graph.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_sanitizers.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_store_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/knowledge_store_supabase.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/loop_detection.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/_loop.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/bridge.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/client.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/config.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/multi.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/mcp/server.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/models.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/langfuse.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/otel.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observe/trace_store.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/parser.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pending.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pipeline.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/pricing.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/prompt.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/_openai_compat.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/anthropic_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/azure_openai_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/base.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/fallback.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/gemini_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/litellm_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/ollama_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/openai_provider.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/router.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/providers/stubs.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/bm25.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/chunking.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/hybrid.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/loaders.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/reranker.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/chroma.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/faiss.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/pgvector.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/pinecone.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/qdrant.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/stores/sqlite.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/rag/vector_store.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/results.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/scheduler.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/security.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_starlette_app.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.css +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.html +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/_static/builder.js +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/api.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/app.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/builder.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/cli.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/models.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/serve/playground.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/stability.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/structured.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/code_reviewer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/customer_support.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/data_analyst.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/rag_chatbot.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/templates/research_assistant.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/token_estimation.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/browser_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/data_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/datetime_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/discord_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/file_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/image_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/memory_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/reasoning_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/s3_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/text_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/toolbox/web_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/__init__.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/base.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/decorators.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/loader.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/tools/registry.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/trace.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/types.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/unified_memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools/usage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/SOURCES.txt +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/dependency_links.txt +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/entry_points.txt +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/requires.txt +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/src/selectools.egg-info/top_level.txt +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_a2a.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_agent_api.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_agent_hitl.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_approval_gate.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_async_observers.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_audit.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_bake_window_hunt.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_budget.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_core.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_security.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_batch1_tools.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_bug_hunt_regression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_cache.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_cache_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_cancellation.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_checkpoint_postgres.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_coherence.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_concurrency_smoke.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_consolidation_regression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_conversation_branching.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_coverage_orchestration.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_document_loaders_extended.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_langfuse_observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_multimodal.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_otel_observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_v0_21_0_apps.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_e2e_v0_21_0_simulations.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_entity_memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_env.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_advanced.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_cli.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_e2e.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_final.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_hardening.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_html_report.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_new_evaluators.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_ralph_bugs.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_release.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_serve.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_v017_features.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_evals_v0191.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_features_in_graph.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_final_coverage_a.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_final_coverage_b.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_guardrails.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_guardrails_injection.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_hardening.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_backend_supabase.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_graph.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_sanitizers.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_store_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_store_supabase.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_stores.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_knowledge_stores_error_handling.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_langfuse_observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_loop_detection.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_mcp.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_mcp_coverage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_async.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_boundary.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_memory_integration.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_model_switching.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_multi_agent_edge_cases.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_multimodal.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_checkpoint.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_e2e.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_evals.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_graph.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_integration.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_primitives.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_orchestration_supervisor.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_otel_observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_parser.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_patterns.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_pending.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_pending_redis_smoke.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_phase1_design_patterns.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_pipeline.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_pipeline_coverage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_policy.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_prompt.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_prompt_compression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_property_based.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_reasoning_strategy.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_remaining_coverage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_results.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_routing_mode.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_scheduler.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_security.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_semantic_cache.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_serve_app_coverage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_serve_cli.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_dynamodb.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_edge_cases.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_mongo.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_sessions_redis.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_simple_observer.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_simulation_evals.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_ssrf.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_stability.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_starlette_app.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured_config.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_structured_tool_results.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_summarize_on_trim.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_templates_coverage.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_terminal_actions.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_token_estimation.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_tool_caching.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_tool_result_compression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace_html.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_trace_store.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_unified_memory.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_unified_memory_config.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_v016_regression.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_v019_features.py +0 -0
- {selectools-0.28.0 → selectools-0.29.0}/tests/test_visual_builder.py +0 -0
- {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.
|
|
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.
|
|
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"
|
|
@@ -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__ = "
|
|
395
|
+
__stability__ = "stable"
|
|
396
396
|
|
|
397
397
|
__all__ = [
|
|
398
398
|
"CheckpointMetadata",
|
|
@@ -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__ = "
|
|
28
|
+
__stability__ = "stable"
|
|
29
29
|
|
|
30
30
|
__all__ = [
|
|
31
31
|
# PlanAndExecute
|
|
@@ -17,7 +17,7 @@ import ast
|
|
|
17
17
|
import math
|
|
18
18
|
from typing import Callable, Dict, Union
|
|
19
19
|
|
|
20
|
-
from ..stability import
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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.
|
|
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": "
|
|
515
|
-
"orchestration.checkpoint": "
|
|
516
|
-
"orchestration.graph": "
|
|
517
|
-
"orchestration.node": "
|
|
518
|
-
"orchestration.state": "
|
|
519
|
-
"orchestration.supervisor": "
|
|
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": "
|
|
522
|
-
"patterns.debate": "
|
|
523
|
-
"patterns.plan_and_execute": "
|
|
524
|
-
"patterns.reflective": "
|
|
525
|
-
"patterns.team_lead": "
|
|
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": "
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|