selectools 0.19.1__tar.gz → 0.19.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {selectools-0.19.1/src/selectools.egg-info → selectools-0.19.2}/PKG-INFO +30 -4
- {selectools-0.19.1 → selectools-0.19.2}/README.md +29 -3
- {selectools-0.19.1 → selectools-0.19.2}/pyproject.toml +1 -1
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/__init__.py +8 -2
- selectools-0.19.2/src/selectools/stability.py +111 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/trace.py +176 -1
- {selectools-0.19.1 → selectools-0.19.2/src/selectools.egg-info}/PKG-INFO +30 -4
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools.egg-info/SOURCES.txt +3 -0
- selectools-0.19.2/tests/test_stability.py +195 -0
- selectools-0.19.2/tests/test_trace_html.py +159 -0
- {selectools-0.19.1 → selectools-0.19.2}/LICENSE +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/setup.cfg +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/_lifecycle.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/_memory_manager.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/_provider_caller.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/_tool_executor.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/config.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/config_groups.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/agent/core.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/analytics.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/audit.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/cache.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/cache_redis.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/cache_semantic.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/cancellation.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/checkpoint_postgres.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/coherence.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/compose.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/anthropic.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/cohere.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/gemini.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/openai.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/embeddings/provider.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/entity_memory.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/env.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/__main__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/badge.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/dataset.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/evaluators.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/generator.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/history.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/html.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/junit.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/llm_evaluators.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/pairwise.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/regression.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/report.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/serve.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/snapshot.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/suite.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/templates.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/evals/types.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/exceptions.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/base.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/format.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/length.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/pii.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/pipeline.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/topic.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/guardrails/toxicity.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/knowledge.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/knowledge_graph.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/knowledge_store_redis.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/knowledge_store_supabase.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/_loop.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/bridge.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/client.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/config.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/multi.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/mcp/server.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/memory.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/models.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/observe/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/observe/trace_store.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/observer.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/checkpoint.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/graph.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/node.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/state.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/orchestration/supervisor.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/parser.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/patterns/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/patterns/debate.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/patterns/plan_and_execute.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/patterns/reflective.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/patterns/team_lead.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/pipeline.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/policy.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/pricing.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/prompt.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/_openai_compat.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/anthropic_provider.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/base.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/fallback.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/gemini_provider.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/ollama_provider.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/openai_provider.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/providers/stubs.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/bm25.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/chunking.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/hybrid.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/loaders.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/reranker.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/stores/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/stores/chroma.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/stores/memory.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/stores/pinecone.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/stores/sqlite.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/rag/vector_store.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/security.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/serve/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/serve/app.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/serve/cli.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/serve/models.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/serve/playground.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/sessions.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/structured.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/code_reviewer.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/customer_support.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/data_analyst.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/rag_chatbot.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/templates/research_assistant.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/token_estimation.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/data_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/datetime_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/file_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/memory_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/text_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/toolbox/web_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/tools/__init__.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/tools/base.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/tools/decorators.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/tools/loader.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/tools/registry.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/types.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools/usage.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools.egg-info/dependency_links.txt +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools.egg-info/entry_points.txt +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools.egg-info/requires.txt +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/src/selectools.egg-info/top_level.txt +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_approval_gate.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_architecture.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_async_observers.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_audit.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_budget.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_bug_hunt_batch1_core.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_bug_hunt_batch1_security.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_bug_hunt_batch1_tools.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_bug_hunt_regression.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_cache.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_cache_redis.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_cancellation.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_coherence.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_concurrency_smoke.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_consolidation_regression.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_conversation_branching.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_entity_memory.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_env.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_advanced.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_e2e.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_final.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_hardening.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_new_evaluators.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_release.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_v017_features.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_evals_v0191.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_features_in_graph.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_guardrails.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_hardening.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_knowledge.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_knowledge_graph.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_knowledge_store_redis.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_knowledge_store_supabase.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_knowledge_stores.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_mcp.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_memory.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_memory_async.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_memory_boundary.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_memory_integration.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_model_switching.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_multi_agent_edge_cases.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_checkpoint.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_e2e.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_evals.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_graph.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_integration.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_primitives.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_orchestration_supervisor.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_parser.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_patterns.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_phase1_design_patterns.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_pipeline.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_policy.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_prompt.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_prompt_compression.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_property_based.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_reasoning_strategy.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_routing_mode.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_security.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_semantic_cache.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_sessions.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_sessions_edge_cases.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_sessions_redis.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_simple_observer.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_simulation_evals.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_structured.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_structured_config.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_structured_tool_results.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_summarize_on_trim.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_terminal_actions.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_token_estimation.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_tool_caching.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_trace.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_v016_regression.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_v019_features.py +0 -0
- {selectools-0.19.1 → selectools-0.19.2}/tests/test_yaml_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: selectools
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.2
|
|
4
4
|
Summary: Production-ready AI agents with tool calling, structured output, execution traces, and RAG. Provider-agnostic (OpenAI, Anthropic, Gemini, Ollama) with fallback chains, batch processing, tool policies, streaming, caching, and cost tracking.
|
|
5
5
|
Author-email: John Nichev <johnnichev@gmail.com>
|
|
6
6
|
Maintainer-email: NichevLabs <support@nichevlabs.com>
|
|
@@ -86,6 +86,32 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
|
|
|
86
86
|
|
|
87
87
|
## What's New in v0.19
|
|
88
88
|
|
|
89
|
+
### v0.19.2 — Enterprise Hardening
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from selectools.stability import stable, beta, deprecated
|
|
93
|
+
from selectools import trace_to_html
|
|
94
|
+
|
|
95
|
+
# Mark your own extensions with stability levels
|
|
96
|
+
@stable
|
|
97
|
+
class MyProductionAgent: ...
|
|
98
|
+
|
|
99
|
+
@beta
|
|
100
|
+
class MyExperimentalFeature: ...
|
|
101
|
+
|
|
102
|
+
@deprecated(since="0.19", replacement="MyProductionAgent")
|
|
103
|
+
class MyOldAgent: ...
|
|
104
|
+
|
|
105
|
+
# Visualise any trace as a waterfall HTML timeline
|
|
106
|
+
Path("trace.html").write_text(trace_to_html(result.trace))
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **Stability markers** — `@stable`, `@beta`, `@deprecated(since, replacement)` for public API signalling
|
|
110
|
+
- **Trace HTML viewer** — `trace_to_html(trace)` renders a standalone waterfall timeline
|
|
111
|
+
- **Deprecation policy** — 2-minor-version window, programmatic introspection via `.__stability__`
|
|
112
|
+
- **Security audit** — all 41 `# nosec` annotations reviewed and published in `docs/SECURITY.md`
|
|
113
|
+
- **Quality infrastructure** — property-based tests (Hypothesis), thread-safety smoke suite, 5 new production simulations (3135 tests total)
|
|
114
|
+
|
|
89
115
|
### v0.19.1 — Advanced Agent Patterns
|
|
90
116
|
|
|
91
117
|
```python
|
|
@@ -437,10 +463,10 @@ report.to_html("report.html")
|
|
|
437
463
|
- **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
|
|
438
464
|
- **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
|
|
439
465
|
- **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
|
|
440
|
-
- **
|
|
466
|
+
- **75 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
|
|
441
467
|
- **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
|
|
442
468
|
- **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
|
|
443
|
-
- **
|
|
469
|
+
- **3135 Tests**: Unit, integration, regression, and E2E with real API calls
|
|
444
470
|
|
|
445
471
|
## Install
|
|
446
472
|
|
|
@@ -1054,7 +1080,7 @@ pytest tests/ -x -q # All tests
|
|
|
1054
1080
|
pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
|
|
1055
1081
|
```
|
|
1056
1082
|
|
|
1057
|
-
|
|
1083
|
+
3135 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, agent patterns, stability markers, trace viewer, and E2E integration with real API calls.
|
|
1058
1084
|
|
|
1059
1085
|
## License
|
|
1060
1086
|
|
|
@@ -26,6 +26,32 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
|
|
|
26
26
|
|
|
27
27
|
## What's New in v0.19
|
|
28
28
|
|
|
29
|
+
### v0.19.2 — Enterprise Hardening
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from selectools.stability import stable, beta, deprecated
|
|
33
|
+
from selectools import trace_to_html
|
|
34
|
+
|
|
35
|
+
# Mark your own extensions with stability levels
|
|
36
|
+
@stable
|
|
37
|
+
class MyProductionAgent: ...
|
|
38
|
+
|
|
39
|
+
@beta
|
|
40
|
+
class MyExperimentalFeature: ...
|
|
41
|
+
|
|
42
|
+
@deprecated(since="0.19", replacement="MyProductionAgent")
|
|
43
|
+
class MyOldAgent: ...
|
|
44
|
+
|
|
45
|
+
# Visualise any trace as a waterfall HTML timeline
|
|
46
|
+
Path("trace.html").write_text(trace_to_html(result.trace))
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **Stability markers** — `@stable`, `@beta`, `@deprecated(since, replacement)` for public API signalling
|
|
50
|
+
- **Trace HTML viewer** — `trace_to_html(trace)` renders a standalone waterfall timeline
|
|
51
|
+
- **Deprecation policy** — 2-minor-version window, programmatic introspection via `.__stability__`
|
|
52
|
+
- **Security audit** — all 41 `# nosec` annotations reviewed and published in `docs/SECURITY.md`
|
|
53
|
+
- **Quality infrastructure** — property-based tests (Hypothesis), thread-safety smoke suite, 5 new production simulations (3135 tests total)
|
|
54
|
+
|
|
29
55
|
### v0.19.1 — Advanced Agent Patterns
|
|
30
56
|
|
|
31
57
|
```python
|
|
@@ -377,10 +403,10 @@ report.to_html("report.html")
|
|
|
377
403
|
- **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
|
|
378
404
|
- **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
|
|
379
405
|
- **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
|
|
380
|
-
- **
|
|
406
|
+
- **75 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
|
|
381
407
|
- **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
|
|
382
408
|
- **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
|
|
383
|
-
- **
|
|
409
|
+
- **3135 Tests**: Unit, integration, regression, and E2E with real API calls
|
|
384
410
|
|
|
385
411
|
## Install
|
|
386
412
|
|
|
@@ -994,7 +1020,7 @@ pytest tests/ -x -q # All tests
|
|
|
994
1020
|
pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
|
|
995
1021
|
```
|
|
996
1022
|
|
|
997
|
-
|
|
1023
|
+
3135 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, agent patterns, stability markers, trace viewer, and E2E integration with real API calls.
|
|
998
1024
|
|
|
999
1025
|
## License
|
|
1000
1026
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "selectools"
|
|
7
|
-
version = "0.19.
|
|
7
|
+
version = "0.19.2"
|
|
8
8
|
description = "Production-ready AI agents with tool calling, structured output, execution traces, and RAG. Provider-agnostic (OpenAI, Anthropic, Gemini, Ollama) with fallback chains, batch processing, tool policies, streaming, caching, and cost tracking."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Public exports for the selectools package."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.19.
|
|
3
|
+
__version__ = "0.19.2"
|
|
4
4
|
|
|
5
5
|
# Import submodules (lazy loading for optional dependencies)
|
|
6
6
|
from . import embeddings, evals, guardrails, models, patterns, rag, toolbox
|
|
@@ -129,10 +129,11 @@ from .sessions import (
|
|
|
129
129
|
SessionStore,
|
|
130
130
|
SQLiteSessionStore,
|
|
131
131
|
)
|
|
132
|
+
from .stability import beta, deprecated, stable
|
|
132
133
|
from .structured import ResponseFormat
|
|
133
134
|
from .token_estimation import TokenEstimate, estimate_run_tokens, estimate_tokens
|
|
134
135
|
from .tools import Tool, ToolParameter, ToolRegistry, tool
|
|
135
|
-
from .trace import AgentTrace, StepType, TraceStep
|
|
136
|
+
from .trace import AgentTrace, StepType, TraceStep, trace_to_html
|
|
136
137
|
from .types import AgentResult, Message, Role, ToolCall
|
|
137
138
|
from .usage import AgentUsage, UsageStats
|
|
138
139
|
|
|
@@ -201,6 +202,10 @@ __all__ = [
|
|
|
201
202
|
"PolicyResult",
|
|
202
203
|
# Structured output
|
|
203
204
|
"ResponseFormat",
|
|
205
|
+
# Stability markers
|
|
206
|
+
"stable",
|
|
207
|
+
"beta",
|
|
208
|
+
"deprecated",
|
|
204
209
|
# Observability
|
|
205
210
|
"AgentObserver",
|
|
206
211
|
"AsyncAgentObserver",
|
|
@@ -209,6 +214,7 @@ __all__ = [
|
|
|
209
214
|
"AgentTrace",
|
|
210
215
|
"StepType",
|
|
211
216
|
"TraceStep",
|
|
217
|
+
"trace_to_html",
|
|
212
218
|
# Guardrails
|
|
213
219
|
"guardrails",
|
|
214
220
|
"Guardrail",
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Stability markers for the selectools public API.
|
|
3
|
+
|
|
4
|
+
Use these decorators to signal the stability of any public function or class:
|
|
5
|
+
|
|
6
|
+
- ``@stable`` — API is frozen; breaking changes require a major version bump.
|
|
7
|
+
- ``@beta`` — API may change in a minor release; no deprecation cycle guaranteed.
|
|
8
|
+
- ``@deprecated(since, replacement)`` — Emits ``DeprecationWarning`` on use and will
|
|
9
|
+
be removed after the minimum deprecation window (2 minor releases).
|
|
10
|
+
|
|
11
|
+
Examples::
|
|
12
|
+
|
|
13
|
+
from selectools.stability import stable, beta, deprecated
|
|
14
|
+
|
|
15
|
+
@stable
|
|
16
|
+
def my_function(): ...
|
|
17
|
+
|
|
18
|
+
@beta
|
|
19
|
+
class MyExperimentalClass: ...
|
|
20
|
+
|
|
21
|
+
@deprecated(since="0.19", replacement="NewThing")
|
|
22
|
+
def old_function(): ...
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import functools
|
|
28
|
+
import inspect
|
|
29
|
+
import warnings
|
|
30
|
+
from typing import Any, Callable, Optional, TypeVar, Union, overload
|
|
31
|
+
|
|
32
|
+
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
33
|
+
_C = TypeVar("_C", bound=type)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def stable(obj: Union[_F, _C]) -> Union[_F, _C]:
|
|
37
|
+
"""Set stability marker to 'stable' (API is frozen)."""
|
|
38
|
+
obj.__stability__ = "stable" # type: ignore[union-attr]
|
|
39
|
+
return obj
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def beta(obj: Union[_F, _C]) -> Union[_F, _C]:
|
|
43
|
+
"""Set stability marker to 'beta' (API may change in minor releases)."""
|
|
44
|
+
obj.__stability__ = "beta" # type: ignore[union-attr]
|
|
45
|
+
return obj
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def deprecated(
|
|
49
|
+
since: str,
|
|
50
|
+
replacement: Optional[str] = None,
|
|
51
|
+
) -> Callable[[Union[_F, _C]], Union[_F, _C]]:
|
|
52
|
+
"""Mark a function or class as deprecated.
|
|
53
|
+
|
|
54
|
+
Emits a ``DeprecationWarning`` on every call or instantiation.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
since: The version in which the deprecation was introduced (e.g. ``"0.19"``).
|
|
58
|
+
replacement: Optional name of the replacement API to suggest in the warning.
|
|
59
|
+
|
|
60
|
+
Example::
|
|
61
|
+
|
|
62
|
+
@deprecated(since="0.19", replacement="NewProvider")
|
|
63
|
+
class OldProvider:
|
|
64
|
+
...
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
def _make_message(name: str) -> str:
|
|
68
|
+
msg = f"{name} is deprecated since v{since}."
|
|
69
|
+
if replacement:
|
|
70
|
+
msg += f" Use {replacement} instead."
|
|
71
|
+
return msg
|
|
72
|
+
|
|
73
|
+
@overload
|
|
74
|
+
def decorator(obj: _C) -> _C: ...
|
|
75
|
+
|
|
76
|
+
@overload
|
|
77
|
+
def decorator(obj: _F) -> _F: ...
|
|
78
|
+
|
|
79
|
+
def decorator(obj: Union[_F, _C]) -> Union[_F, _C]:
|
|
80
|
+
if inspect.isclass(obj):
|
|
81
|
+
# Wrap __init__ so the warning fires on instantiation.
|
|
82
|
+
original_init = obj.__init__ # type: ignore[misc]
|
|
83
|
+
message = _make_message(obj.__qualname__)
|
|
84
|
+
|
|
85
|
+
@functools.wraps(original_init)
|
|
86
|
+
def _new_init(self: Any, *args: Any, **kwargs: Any) -> None:
|
|
87
|
+
warnings.warn(message, DeprecationWarning, stacklevel=2)
|
|
88
|
+
original_init(self, *args, **kwargs)
|
|
89
|
+
|
|
90
|
+
obj.__init__ = _new_init # type: ignore[method-assign]
|
|
91
|
+
obj.__stability__ = "deprecated" # type: ignore[union-attr]
|
|
92
|
+
obj.__deprecated_since__ = since # type: ignore[union-attr]
|
|
93
|
+
obj.__deprecated_replacement__ = replacement # type: ignore[union-attr]
|
|
94
|
+
return obj # type: ignore[return-value]
|
|
95
|
+
else:
|
|
96
|
+
message = _make_message(obj.__qualname__)
|
|
97
|
+
|
|
98
|
+
@functools.wraps(obj)
|
|
99
|
+
def _wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
100
|
+
warnings.warn(message, DeprecationWarning, stacklevel=2)
|
|
101
|
+
return obj(*args, **kwargs)
|
|
102
|
+
|
|
103
|
+
_wrapper.__stability__ = "deprecated" # type: ignore[attr-defined]
|
|
104
|
+
_wrapper.__deprecated_since__ = since # type: ignore[attr-defined]
|
|
105
|
+
_wrapper.__deprecated_replacement__ = replacement # type: ignore[attr-defined]
|
|
106
|
+
return _wrapper # type: ignore[return-value]
|
|
107
|
+
|
|
108
|
+
return decorator # type: ignore[return-value]
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
__all__ = ["stable", "beta", "deprecated"]
|
|
@@ -300,4 +300,179 @@ def _span_id() -> str:
|
|
|
300
300
|
return uuid.uuid4().hex[:16]
|
|
301
301
|
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
# ---------------------------------------------------------------------------
|
|
304
|
+
# HTML trace viewer
|
|
305
|
+
# ---------------------------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
_STEP_COLORS: Dict[str, str] = {
|
|
308
|
+
"llm_call": "#3b82f6",
|
|
309
|
+
"tool_execution": "#8b5cf6",
|
|
310
|
+
"tool_selection": "#a78bfa",
|
|
311
|
+
"cache_hit": "#4ade80",
|
|
312
|
+
"error": "#f87171",
|
|
313
|
+
"guardrail": "#fbbf24",
|
|
314
|
+
"output_screening": "#fbbf24",
|
|
315
|
+
"coherence_check": "#fbbf24",
|
|
316
|
+
"graph_node_start": "#06b6d4",
|
|
317
|
+
"graph_node_end": "#06b6d4",
|
|
318
|
+
"graph_routing": "#06b6d4",
|
|
319
|
+
"graph_checkpoint": "#06b6d4",
|
|
320
|
+
"graph_interrupt": "#06b6d4",
|
|
321
|
+
"graph_resume": "#06b6d4",
|
|
322
|
+
"graph_parallel_start": "#06b6d4",
|
|
323
|
+
"graph_parallel_end": "#06b6d4",
|
|
324
|
+
"graph_stall": "#f97316",
|
|
325
|
+
"graph_loop_detected": "#f97316",
|
|
326
|
+
}
|
|
327
|
+
_DEFAULT_COLOR = "#64748b"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def trace_to_html(trace: "AgentTrace") -> str:
|
|
331
|
+
"""Render an AgentTrace as a standalone HTML waterfall timeline.
|
|
332
|
+
|
|
333
|
+
Returns a self-contained HTML string (no external dependencies).
|
|
334
|
+
The caller is responsible for writing it to disk if desired::
|
|
335
|
+
|
|
336
|
+
from selectools import trace_to_html
|
|
337
|
+
Path("trace.html").write_text(trace_to_html(result.trace))
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
trace: The ``AgentTrace`` to visualise.
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
A complete HTML document as a string.
|
|
344
|
+
"""
|
|
345
|
+
import html as _html
|
|
346
|
+
|
|
347
|
+
max_dur = max((s.duration_ms for s in trace.steps), default=1.0)
|
|
348
|
+
max_dur = max(max_dur, 1.0) # guard against all-zero durations
|
|
349
|
+
|
|
350
|
+
total_ms = trace.total_duration_ms
|
|
351
|
+
llm_ms = trace.llm_duration_ms
|
|
352
|
+
tool_ms = trace.tool_duration_ms
|
|
353
|
+
llm_pct = f"{llm_ms / max(total_ms, 1) * 100:.0f}%"
|
|
354
|
+
tool_pct = f"{tool_ms / max(total_ms, 1) * 100:.0f}%"
|
|
355
|
+
|
|
356
|
+
def _esc(v: Any) -> str:
|
|
357
|
+
return _html.escape(str(v)) if v is not None else ""
|
|
358
|
+
|
|
359
|
+
def _detail(step: "TraceStep") -> str:
|
|
360
|
+
parts = []
|
|
361
|
+
if step.model:
|
|
362
|
+
parts.append(f"<b>model:</b> {_esc(step.model)}")
|
|
363
|
+
if step.prompt_tokens is not None:
|
|
364
|
+
parts.append(f"<b>prompt tokens:</b> {step.prompt_tokens}")
|
|
365
|
+
if step.completion_tokens is not None:
|
|
366
|
+
parts.append(f"<b>completion tokens:</b> {step.completion_tokens}")
|
|
367
|
+
if step.cost_usd is not None:
|
|
368
|
+
parts.append(f"<b>cost:</b> ${step.cost_usd:.6f}")
|
|
369
|
+
if step.tool_name:
|
|
370
|
+
parts.append(f"<b>tool:</b> {_esc(step.tool_name)}")
|
|
371
|
+
if step.tool_args:
|
|
372
|
+
parts.append(f"<b>args:</b> <code>{_esc(json.dumps(step.tool_args))}</code>")
|
|
373
|
+
if step.tool_result:
|
|
374
|
+
truncated = str(step.tool_result)[:300]
|
|
375
|
+
parts.append(f"<b>result:</b> <code>{_esc(truncated)}</code>")
|
|
376
|
+
if step.error:
|
|
377
|
+
parts.append(f"<b>error:</b> <span style='color:#f87171'>{_esc(step.error)}</span>")
|
|
378
|
+
if step.node_name:
|
|
379
|
+
parts.append(f"<b>node:</b> {_esc(step.node_name)}")
|
|
380
|
+
if step.from_node or step.to_node:
|
|
381
|
+
parts.append(f"<b>route:</b> {_esc(step.from_node)} → {_esc(step.to_node)}")
|
|
382
|
+
if step.summary:
|
|
383
|
+
parts.append(f"<b>summary:</b> {_esc(step.summary)}")
|
|
384
|
+
if step.reasoning:
|
|
385
|
+
parts.append(f"<b>reasoning:</b> {_esc(step.reasoning[:200])}")
|
|
386
|
+
return "<br>".join(parts) if parts else "<i>no details</i>"
|
|
387
|
+
|
|
388
|
+
rows = []
|
|
389
|
+
for i, step in enumerate(trace.steps):
|
|
390
|
+
type_val = step.type.value if hasattr(step.type, "value") else str(step.type)
|
|
391
|
+
color = _STEP_COLORS.get(type_val, _DEFAULT_COLOR)
|
|
392
|
+
bar_pct = step.duration_ms / max_dur * 100
|
|
393
|
+
label = step.summary or type_val
|
|
394
|
+
detail_html = _detail(step)
|
|
395
|
+
rows.append(
|
|
396
|
+
f"""
|
|
397
|
+
<tr onclick="toggleDetail('d{i}')" style="cursor:pointer">
|
|
398
|
+
<td style="color:#94a3b8;width:32px;text-align:right;padding-right:12px">{i + 1}</td>
|
|
399
|
+
<td style="width:160px">
|
|
400
|
+
<span style="background:{color};color:#0f172a;font-size:11px;font-weight:600;
|
|
401
|
+
padding:2px 7px;border-radius:4px">{_esc(type_val)}</span>
|
|
402
|
+
</td>
|
|
403
|
+
<td style="width:200px;padding:0 12px">
|
|
404
|
+
<div style="background:#1e3a5f;border-radius:3px;height:10px;width:100%">
|
|
405
|
+
<div style="background:{color};border-radius:3px;height:10px;width:{bar_pct:.1f}%"></div>
|
|
406
|
+
</div>
|
|
407
|
+
</td>
|
|
408
|
+
<td style="color:#94a3b8;width:70px;text-align:right;padding-right:12px">
|
|
409
|
+
{step.duration_ms:.1f}ms
|
|
410
|
+
</td>
|
|
411
|
+
<td style="color:#e2e8f0">{_esc(label)}</td>
|
|
412
|
+
</tr>
|
|
413
|
+
<tr id="d{i}" style="display:none">
|
|
414
|
+
<td colspan="5" style="padding:8px 16px 12px 44px;color:#94a3b8;
|
|
415
|
+
font-size:12px;background:#0f2035;border-bottom:1px solid #1e3a5f">
|
|
416
|
+
{detail_html}
|
|
417
|
+
</td>
|
|
418
|
+
</tr>"""
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
rows_html = "\n".join(rows)
|
|
422
|
+
run_id_display = _esc(trace.run_id[:16]) + "…" if len(trace.run_id) > 16 else _esc(trace.run_id)
|
|
423
|
+
step_count = len(trace.steps)
|
|
424
|
+
|
|
425
|
+
return f"""<!DOCTYPE html>
|
|
426
|
+
<html lang="en">
|
|
427
|
+
<head>
|
|
428
|
+
<meta charset="utf-8">
|
|
429
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
430
|
+
<title>Agent Trace — {run_id_display}</title>
|
|
431
|
+
<style>
|
|
432
|
+
* {{ box-sizing: border-box; margin: 0; padding: 0; }}
|
|
433
|
+
body {{ background: #0f172a; color: #e2e8f0; font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
434
|
+
font-size: 13px; padding: 24px; }}
|
|
435
|
+
h1 {{ font-size: 16px; font-weight: 600; color: #f8fafc; margin-bottom: 4px; }}
|
|
436
|
+
.meta {{ color: #64748b; font-size: 12px; margin-bottom: 24px; }}
|
|
437
|
+
.stat {{ display: inline-block; margin-right: 24px; }}
|
|
438
|
+
.stat b {{ color: #e2e8f0; }}
|
|
439
|
+
table {{ width: 100%; border-collapse: collapse; }}
|
|
440
|
+
tr:hover td {{ background: #1a2744; }}
|
|
441
|
+
td {{ padding: 7px 4px; border-bottom: 1px solid #1e293b; vertical-align: middle; }}
|
|
442
|
+
code {{ background: #1e293b; padding: 1px 4px; border-radius: 3px; font-size: 11px; }}
|
|
443
|
+
</style>
|
|
444
|
+
</head>
|
|
445
|
+
<body>
|
|
446
|
+
<h1>Agent Trace</h1>
|
|
447
|
+
<div class="meta">
|
|
448
|
+
<span class="stat"><b>run:</b> {run_id_display}</span>
|
|
449
|
+
<span class="stat"><b>steps:</b> {step_count}</span>
|
|
450
|
+
<span class="stat"><b>total:</b> {total_ms:.1f}ms</span>
|
|
451
|
+
<span class="stat"><b>llm:</b> {llm_ms:.1f}ms ({llm_pct})</span>
|
|
452
|
+
<span class="stat"><b>tools:</b> {tool_ms:.1f}ms ({tool_pct})</span>
|
|
453
|
+
</div>
|
|
454
|
+
<table>
|
|
455
|
+
<thead>
|
|
456
|
+
<tr>
|
|
457
|
+
<th style="color:#475569;text-align:right;padding-right:12px">#</th>
|
|
458
|
+
<th style="color:#475569;text-align:left">type</th>
|
|
459
|
+
<th style="color:#475569;padding:0 12px">duration</th>
|
|
460
|
+
<th style="color:#475569;text-align:right;padding-right:12px">ms</th>
|
|
461
|
+
<th style="color:#475569;text-align:left">label</th>
|
|
462
|
+
</tr>
|
|
463
|
+
</thead>
|
|
464
|
+
<tbody>
|
|
465
|
+
{rows_html}
|
|
466
|
+
</tbody>
|
|
467
|
+
</table>
|
|
468
|
+
<script>
|
|
469
|
+
function toggleDetail(id) {{
|
|
470
|
+
var el = document.getElementById(id);
|
|
471
|
+
el.style.display = el.style.display === 'none' ? 'table-row' : 'none';
|
|
472
|
+
}}
|
|
473
|
+
</script>
|
|
474
|
+
</body>
|
|
475
|
+
</html>"""
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
__all__ = ["TraceStep", "AgentTrace", "StepType", "trace_to_html"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: selectools
|
|
3
|
-
Version: 0.19.
|
|
3
|
+
Version: 0.19.2
|
|
4
4
|
Summary: Production-ready AI agents with tool calling, structured output, execution traces, and RAG. Provider-agnostic (OpenAI, Anthropic, Gemini, Ollama) with fallback chains, batch processing, tool policies, streaming, caching, and cost tracking.
|
|
5
5
|
Author-email: John Nichev <johnnichev@gmail.com>
|
|
6
6
|
Maintainer-email: NichevLabs <support@nichevlabs.com>
|
|
@@ -86,6 +86,32 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
|
|
|
86
86
|
|
|
87
87
|
## What's New in v0.19
|
|
88
88
|
|
|
89
|
+
### v0.19.2 — Enterprise Hardening
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from selectools.stability import stable, beta, deprecated
|
|
93
|
+
from selectools import trace_to_html
|
|
94
|
+
|
|
95
|
+
# Mark your own extensions with stability levels
|
|
96
|
+
@stable
|
|
97
|
+
class MyProductionAgent: ...
|
|
98
|
+
|
|
99
|
+
@beta
|
|
100
|
+
class MyExperimentalFeature: ...
|
|
101
|
+
|
|
102
|
+
@deprecated(since="0.19", replacement="MyProductionAgent")
|
|
103
|
+
class MyOldAgent: ...
|
|
104
|
+
|
|
105
|
+
# Visualise any trace as a waterfall HTML timeline
|
|
106
|
+
Path("trace.html").write_text(trace_to_html(result.trace))
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **Stability markers** — `@stable`, `@beta`, `@deprecated(since, replacement)` for public API signalling
|
|
110
|
+
- **Trace HTML viewer** — `trace_to_html(trace)` renders a standalone waterfall timeline
|
|
111
|
+
- **Deprecation policy** — 2-minor-version window, programmatic introspection via `.__stability__`
|
|
112
|
+
- **Security audit** — all 41 `# nosec` annotations reviewed and published in `docs/SECURITY.md`
|
|
113
|
+
- **Quality infrastructure** — property-based tests (Hypothesis), thread-safety smoke suite, 5 new production simulations (3135 tests total)
|
|
114
|
+
|
|
89
115
|
### v0.19.1 — Advanced Agent Patterns
|
|
90
116
|
|
|
91
117
|
```python
|
|
@@ -437,10 +463,10 @@ report.to_html("report.html")
|
|
|
437
463
|
- **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
|
|
438
464
|
- **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
|
|
439
465
|
- **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
|
|
440
|
-
- **
|
|
466
|
+
- **75 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
|
|
441
467
|
- **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
|
|
442
468
|
- **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
|
|
443
|
-
- **
|
|
469
|
+
- **3135 Tests**: Unit, integration, regression, and E2E with real API calls
|
|
444
470
|
|
|
445
471
|
## Install
|
|
446
472
|
|
|
@@ -1054,7 +1080,7 @@ pytest tests/ -x -q # All tests
|
|
|
1054
1080
|
pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
|
|
1055
1081
|
```
|
|
1056
1082
|
|
|
1057
|
-
|
|
1083
|
+
3135 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, agent patterns, stability markers, trace viewer, and E2E integration with real API calls.
|
|
1058
1084
|
|
|
1059
1085
|
## License
|
|
1060
1086
|
|
|
@@ -28,6 +28,7 @@ src/selectools/pricing.py
|
|
|
28
28
|
src/selectools/prompt.py
|
|
29
29
|
src/selectools/security.py
|
|
30
30
|
src/selectools/sessions.py
|
|
31
|
+
src/selectools/stability.py
|
|
31
32
|
src/selectools/structured.py
|
|
32
33
|
src/selectools/token_estimation.py
|
|
33
34
|
src/selectools/trace.py
|
|
@@ -210,6 +211,7 @@ tests/test_sessions_edge_cases.py
|
|
|
210
211
|
tests/test_sessions_redis.py
|
|
211
212
|
tests/test_simple_observer.py
|
|
212
213
|
tests/test_simulation_evals.py
|
|
214
|
+
tests/test_stability.py
|
|
213
215
|
tests/test_structured.py
|
|
214
216
|
tests/test_structured_config.py
|
|
215
217
|
tests/test_structured_tool_results.py
|
|
@@ -218,6 +220,7 @@ tests/test_terminal_actions.py
|
|
|
218
220
|
tests/test_token_estimation.py
|
|
219
221
|
tests/test_tool_caching.py
|
|
220
222
|
tests/test_trace.py
|
|
223
|
+
tests/test_trace_html.py
|
|
221
224
|
tests/test_v016_regression.py
|
|
222
225
|
tests/test_v019_features.py
|
|
223
226
|
tests/test_yaml_config.py
|