chuk-tool-processor 0.17__tar.gz → 0.19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/PKG-INFO +124 -1
  2. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/README.md +123 -0
  3. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/pyproject.toml +1 -1
  4. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/__init__.py +172 -0
  5. chuk_tool_processor-0.19/src/chuk_tool_processor/discovery/__init__.py +77 -0
  6. chuk_tool_processor-0.19/src/chuk_tool_processor/discovery/dynamic_provider.py +629 -0
  7. chuk_tool_processor-0.19/src/chuk_tool_processor/discovery/search.py +883 -0
  8. chuk_tool_processor-0.19/src/chuk_tool_processor/discovery/searchable.py +97 -0
  9. chuk_tool_processor-0.19/src/chuk_tool_processor/discovery/synonyms.py +752 -0
  10. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/__init__.py +7 -0
  11. chuk_tool_processor-0.19/src/chuk_tool_processor/execution/wrappers/observable.py +417 -0
  12. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/__init__.py +246 -0
  13. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/assumption_trace.py +445 -0
  14. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/base.py +140 -0
  15. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/budget.py +201 -0
  16. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/chain.py +275 -0
  17. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/concurrency.py +208 -0
  18. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/contract_guard.py +250 -0
  19. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/models.py +202 -0
  20. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/network_policy.py +306 -0
  21. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/output_size.py +290 -0
  22. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/per_tool.py +121 -0
  23. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/plan_shape.py +349 -0
  24. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/precondition.py +177 -0
  25. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/provenance.py +276 -0
  26. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/retry_safety.py +335 -0
  27. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/runaway.py +129 -0
  28. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/saturation.py +215 -0
  29. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/schema_strictness.py +350 -0
  30. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/sensitive_data.py +283 -0
  31. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/side_effect.py +273 -0
  32. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/timeout_budget.py +261 -0
  33. chuk_tool_processor-0.19/src/chuk_tool_processor/guards/unresolved.py +139 -0
  34. chuk_tool_processor-0.19/src/chuk_tool_processor/models/__init__.py +94 -0
  35. chuk_tool_processor-0.19/src/chuk_tool_processor/models/execution_span.py +651 -0
  36. chuk_tool_processor-0.19/src/chuk_tool_processor/models/execution_trace.py +571 -0
  37. chuk_tool_processor-0.19/src/chuk_tool_processor/models/sandbox_policy.py +552 -0
  38. chuk_tool_processor-0.19/src/chuk_tool_processor/models/tool_contract.py +552 -0
  39. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/tool_spec.py +80 -1
  40. chuk_tool_processor-0.19/src/chuk_tool_processor/observability/__init__.py +68 -0
  41. chuk_tool_processor-0.19/src/chuk_tool_processor/observability/trace_sink.py +677 -0
  42. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor.egg-info/PKG-INFO +124 -1
  43. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor.egg-info/SOURCES.txt +33 -0
  44. chuk_tool_processor-0.17/src/chuk_tool_processor/models/__init__.py +0 -21
  45. chuk_tool_processor-0.17/src/chuk_tool_processor/observability/__init__.py +0 -30
  46. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/setup.cfg +0 -0
  47. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/config.py +0 -0
  48. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/core/__init__.py +0 -0
  49. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/core/context.py +0 -0
  50. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/core/exceptions.py +0 -0
  51. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/core/processor.py +0 -0
  52. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/__init__.py +0 -0
  53. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/bulkhead.py +0 -0
  54. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/code_sandbox.py +0 -0
  55. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/strategies/__init__.py +0 -0
  56. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/strategies/inprocess_strategy.py +0 -0
  57. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/strategies/subprocess_strategy.py +0 -0
  58. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/tool_executor.py +0 -0
  59. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/caching.py +0 -0
  60. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/circuit_breaker.py +0 -0
  61. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/factory.py +0 -0
  62. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/rate_limiting.py +0 -0
  63. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/redis_circuit_breaker.py +0 -0
  64. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/redis_rate_limiting.py +0 -0
  65. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/execution/wrappers/retry.py +0 -0
  66. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/logging/__init__.py +0 -0
  67. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/logging/context.py +0 -0
  68. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/logging/formatter.py +0 -0
  69. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/logging/helpers.py +0 -0
  70. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/logging/metrics.py +0 -0
  71. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/__init__.py +0 -0
  72. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/mcp_tool.py +0 -0
  73. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/middleware.py +0 -0
  74. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/models.py +0 -0
  75. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/register_mcp_tools.py +0 -0
  76. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/setup_mcp_http_streamable.py +0 -0
  77. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/setup_mcp_sse.py +0 -0
  78. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/setup_mcp_stdio.py +0 -0
  79. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/stream_manager.py +0 -0
  80. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/__init__.py +0 -0
  81. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/base_transport.py +0 -0
  82. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/http_streamable_transport.py +0 -0
  83. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/models.py +0 -0
  84. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/sse_transport.py +0 -0
  85. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/mcp/transport/stdio_transport.py +0 -0
  86. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/execution_strategy.py +0 -0
  87. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/return_order.py +0 -0
  88. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/streaming_tool.py +0 -0
  89. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/tool_call.py +0 -0
  90. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/tool_export_mixin.py +0 -0
  91. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/tool_result.py +0 -0
  92. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/models/validated_tool.py +0 -0
  93. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/observability/metrics.py +0 -0
  94. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/observability/setup.py +0 -0
  95. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/observability/tracing.py +0 -0
  96. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/__init__.py +0 -0
  97. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/discovery.py +0 -0
  98. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/__init__.py +0 -0
  99. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/base.py +0 -0
  100. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/function_call_tool.py +0 -0
  101. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/json_tool.py +0 -0
  102. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/openai_tool.py +0 -0
  103. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/plugins/parsers/xml_tool.py +0 -0
  104. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/py.typed +0 -0
  105. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/__init__.py +0 -0
  106. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/auto_register.py +0 -0
  107. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/decorators.py +0 -0
  108. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/interface.py +0 -0
  109. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/metadata.py +0 -0
  110. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/provider.py +0 -0
  111. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/providers/__init__.py +0 -0
  112. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/providers/memory.py +0 -0
  113. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/providers/redis.py +0 -0
  114. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/registry/tool_export.py +0 -0
  115. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/scheduling/__init__.py +0 -0
  116. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/scheduling/greedy_dag.py +0 -0
  117. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/scheduling/policy.py +0 -0
  118. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/scheduling/types.py +0 -0
  119. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/utils/__init__.py +0 -0
  120. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/utils/fast_json.py +0 -0
  121. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor/utils/validation.py +0 -0
  122. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor.egg-info/dependency_links.txt +0 -0
  123. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor.egg-info/requires.txt +0 -0
  124. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/src/chuk_tool_processor.egg-info/top_level.txt +0 -0
  125. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/tests/test_bulkhead.py +0 -0
  126. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/tests/test_execution_context.py +0 -0
  127. {chuk_tool_processor-0.17 → chuk_tool_processor-0.19}/tests/test_scoped_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chuk-tool-processor
3
- Version: 0.17
3
+ Version: 0.19
4
4
  Summary: Async-native framework for registering, discovering, and executing tools referenced in LLM responses
5
5
  Author-email: CHUK Team <chrishayuk@somejunkmailbox.com>
6
6
  Maintainer-email: CHUK Team <chrishayuk@somejunkmailbox.com>
@@ -208,6 +208,32 @@ results = await processor.process(json_output)
208
208
  | **SchedulerPolicy** | DAG-based scheduling with dependencies, deadlines, pool limits |
209
209
  | **GreedyDagScheduler** | Built-in scheduler with topological sort and deadline-aware skipping |
210
210
 
211
+ ### Runtime Guards (Constitution Layer)
212
+
213
+ | Guard | Description |
214
+ |-------|-------------|
215
+ | **SchemaStrictnessGuard** | Validates arguments against JSON schemas, optional type coercion |
216
+ | **SensitiveDataGuard** | Detects and blocks/redacts secrets (API keys, JWTs, private keys) |
217
+ | **NetworkPolicyGuard** | SSRF defense — blocks private IPs, metadata endpoints, enforces HTTPS |
218
+ | **SideEffectGuard** | Labels tools as read_only/write/destructive, enforces policies |
219
+ | **ConcurrencyGuard** | Limits simultaneous in-flight calls (global, per-tool, per-namespace) |
220
+ | **TimeoutBudgetGuard** | Enforces wall-clock time budgets with soft/hard limits |
221
+ | **OutputSizeGuard** | Prevents pathological payloads from blowing up context |
222
+ | **RetrySafetyGuard** | Guards retry behavior (backoff, idempotency keys, non-retryable errors) |
223
+ | **ProvenanceGuard** | Tracks output attribution and lineage |
224
+ | **PlanShapeGuard** | Detects pathological patterns (fan-out explosions, long chains) |
225
+ | **SaturationGuard** | Detects degenerate statistical outputs (extreme Z-scores, saturated CDFs) |
226
+
227
+ ### Dynamic Tool Discovery
228
+
229
+ | Feature | Description |
230
+ |---------|-------------|
231
+ | **Intelligent Search** | Natural language queries find tools ("gaussian" → "normal_cdf") |
232
+ | **Synonym Expansion** | Built-in synonyms for math, statistics, file ops, networking |
233
+ | **Fuzzy Matching** | Typo tolerance ("multipley" finds "multiply") |
234
+ | **Session Boosting** | Recently used tools rank higher in search results |
235
+ | **Dynamic Provider** | Base class for LLM-driven tool discovery and execution |
236
+
211
237
  ### Integration & Observability
212
238
 
213
239
  | Feature | Description |
@@ -434,6 +460,95 @@ See [examples/02_production_features/distributed_config_demo.py](examples/02_pro
434
460
 
435
461
  ---
436
462
 
463
+ ## Runtime Guards
464
+
465
+ Protect your tool execution with composable guards that enforce safety policies:
466
+
467
+ ```python
468
+ from chuk_tool_processor.guards import (
469
+ GuardChain,
470
+ SchemaStrictnessGuard,
471
+ SensitiveDataGuard,
472
+ NetworkPolicyGuard,
473
+ ConcurrencyGuard,
474
+ )
475
+
476
+ # Create individual guards
477
+ schema_guard = SchemaStrictnessGuard(get_schema=my_schema_getter)
478
+ sensitive_guard = SensitiveDataGuard() # Detects API keys, JWTs, etc.
479
+ network_guard = NetworkPolicyGuard(block_private_ips=True)
480
+ concurrency_guard = ConcurrencyGuard(global_max=50, per_tool_max={"heavy_api": 2})
481
+
482
+ # Compose into a chain
483
+ chain = GuardChain([schema_guard, sensitive_guard, network_guard, concurrency_guard])
484
+
485
+ # Check before execution
486
+ result = await chain.check_all_async("api.fetch", {"url": "https://example.com"})
487
+ if result.blocked:
488
+ print(f"Blocked by {result.stopped_at}: {result.reason}")
489
+ ```
490
+
491
+ **Key Guards:**
492
+ - **SchemaStrictnessGuard** — Validate args against JSON schemas, auto-coerce types
493
+ - **SensitiveDataGuard** — Block or redact secrets (API keys, JWTs, private keys)
494
+ - **NetworkPolicyGuard** — SSRF defense (block localhost, private IPs, metadata endpoints)
495
+ - **SideEffectGuard** — Enforce read-only mode, block destructive ops in production
496
+ - **ConcurrencyGuard** — Limit in-flight calls globally, per-tool, or per-namespace
497
+ - **TimeoutBudgetGuard** — Enforce wall-clock budgets with soft/hard limits
498
+ - **OutputSizeGuard** — Prevent pathological payloads (size, depth, array length)
499
+ - **SaturationGuard** — Detect degenerate statistical outputs (extreme Z-scores, saturated CDFs)
500
+
501
+ See [GUARDS.md](docs/GUARDS.md) for complete documentation and examples.
502
+
503
+ ---
504
+
505
+ ## Dynamic Tool Discovery
506
+
507
+ When you have hundreds of tools, LLMs can't load all schemas upfront. The discovery module provides intelligent search and on-demand tool loading:
508
+
509
+ ```python
510
+ from chuk_tool_processor.discovery import ToolSearchEngine, BaseDynamicToolProvider
511
+
512
+ # Create a search engine for your tools
513
+ engine = ToolSearchEngine()
514
+ engine.set_tools(my_tools)
515
+
516
+ # Natural language search with synonym expansion
517
+ results = engine.search("gaussian distribution") # Finds "normal_cdf"
518
+ results = engine.search("find the average") # Finds "calculate_mean"
519
+ results = engine.search("multipley") # Finds "multiply" (typo tolerance)
520
+
521
+ # Session boosting - recently used tools rank higher
522
+ engine.record_tool_use("calculate_mean", success=True)
523
+ engine.advance_turn()
524
+ results = engine.search("calculate") # "calculate_mean" now boosted
525
+ ```
526
+
527
+ **Dynamic Provider Pattern** — give LLMs meta-tools for discovery:
528
+
529
+ ```python
530
+ class MyToolProvider(BaseDynamicToolProvider):
531
+ async def get_all_tools(self) -> list[Tool]:
532
+ return self._tools
533
+
534
+ async def execute_tool(self, name: str, args: dict) -> dict:
535
+ return await self._tools[name].execute(**args)
536
+
537
+ provider = MyToolProvider()
538
+
539
+ # LLM gets 4 meta-tools: list_tools, search_tools, get_tool_schema, call_tool
540
+ tools_for_llm = provider.get_dynamic_tools()
541
+
542
+ # LLM workflow: search → get schema → call
543
+ results = await provider.search_tools("calculate average")
544
+ schema = await provider.get_tool_schema("calculate_mean")
545
+ result = await provider.call_tool("calculate_mean", {"values": [1, 2, 3]})
546
+ ```
547
+
548
+ See [DISCOVERY.md](docs/DISCOVERY.md) for complete documentation.
549
+
550
+ ---
551
+
437
552
  ## Observability
438
553
 
439
554
  One-line setup for production monitoring:
@@ -491,6 +606,8 @@ See [ERRORS.md](docs/ERRORS.md) for complete error taxonomy.
491
606
  | [**GETTING_STARTED.md**](docs/GETTING_STARTED.md) | Creating tools, using the processor, ValidatedTool, StreamingTool |
492
607
  | [**CORE_CONCEPTS.md**](docs/CORE_CONCEPTS.md) | Registry, strategies, wrappers, parsers, MCP overview |
493
608
  | [**PRODUCTION_PATTERNS.md**](docs/PRODUCTION_PATTERNS.md) | Bulkheads, scoped registries, ExecutionContext, parallel execution |
609
+ | [**DISCOVERY.md**](docs/DISCOVERY.md) | Dynamic tool discovery, intelligent search, synonym expansion |
610
+ | [**GUARDS.md**](docs/GUARDS.md) | Runtime guards for safety, validation, and resource management |
494
611
  | [**MCP_INTEGRATION.md**](docs/MCP_INTEGRATION.md) | HTTP Streamable, STDIO, SSE, OAuth, Middleware Stack |
495
612
  | [**ADVANCED_TOPICS.md**](docs/ADVANCED_TOPICS.md) | Deferred loading, code sandbox, isolated strategy, testing |
496
613
  | [**CONFIGURATION.md**](docs/CONFIGURATION.md) | All config options and environment variables |
@@ -505,6 +622,9 @@ See [ERRORS.md](docs/ERRORS.md) for complete error taxonomy.
505
622
  # Getting started
506
623
  python examples/01_getting_started/hello_tool.py
507
624
 
625
+ # Dynamic tool discovery (search, synonyms, fuzzy matching)
626
+ python examples/07_discovery/dynamic_tools_demo.py
627
+
508
628
  # Hero demo: 8 tools, 5-second deadline, 3 pools (DAG + bulkheads + context)
509
629
  python examples/02_production_features/hero_runtime_demo.py
510
630
 
@@ -517,6 +637,9 @@ python examples/02_production_features/runtime_features_demo.py
517
637
  # Structured error handling for planners
518
638
  python examples/02_production_features/structured_errors_demo.py
519
639
 
640
+ # Runtime guards (validation, security, resource limits)
641
+ python examples/guards_demo.py
642
+
520
643
  # Redis registry for distributed deployments
521
644
  python examples/02_production_features/redis_registry_demo.py
522
645
 
@@ -171,6 +171,32 @@ results = await processor.process(json_output)
171
171
  | **SchedulerPolicy** | DAG-based scheduling with dependencies, deadlines, pool limits |
172
172
  | **GreedyDagScheduler** | Built-in scheduler with topological sort and deadline-aware skipping |
173
173
 
174
+ ### Runtime Guards (Constitution Layer)
175
+
176
+ | Guard | Description |
177
+ |-------|-------------|
178
+ | **SchemaStrictnessGuard** | Validates arguments against JSON schemas, optional type coercion |
179
+ | **SensitiveDataGuard** | Detects and blocks/redacts secrets (API keys, JWTs, private keys) |
180
+ | **NetworkPolicyGuard** | SSRF defense — blocks private IPs, metadata endpoints, enforces HTTPS |
181
+ | **SideEffectGuard** | Labels tools as read_only/write/destructive, enforces policies |
182
+ | **ConcurrencyGuard** | Limits simultaneous in-flight calls (global, per-tool, per-namespace) |
183
+ | **TimeoutBudgetGuard** | Enforces wall-clock time budgets with soft/hard limits |
184
+ | **OutputSizeGuard** | Prevents pathological payloads from blowing up context |
185
+ | **RetrySafetyGuard** | Guards retry behavior (backoff, idempotency keys, non-retryable errors) |
186
+ | **ProvenanceGuard** | Tracks output attribution and lineage |
187
+ | **PlanShapeGuard** | Detects pathological patterns (fan-out explosions, long chains) |
188
+ | **SaturationGuard** | Detects degenerate statistical outputs (extreme Z-scores, saturated CDFs) |
189
+
190
+ ### Dynamic Tool Discovery
191
+
192
+ | Feature | Description |
193
+ |---------|-------------|
194
+ | **Intelligent Search** | Natural language queries find tools ("gaussian" → "normal_cdf") |
195
+ | **Synonym Expansion** | Built-in synonyms for math, statistics, file ops, networking |
196
+ | **Fuzzy Matching** | Typo tolerance ("multipley" finds "multiply") |
197
+ | **Session Boosting** | Recently used tools rank higher in search results |
198
+ | **Dynamic Provider** | Base class for LLM-driven tool discovery and execution |
199
+
174
200
  ### Integration & Observability
175
201
 
176
202
  | Feature | Description |
@@ -397,6 +423,95 @@ See [examples/02_production_features/distributed_config_demo.py](examples/02_pro
397
423
 
398
424
  ---
399
425
 
426
+ ## Runtime Guards
427
+
428
+ Protect your tool execution with composable guards that enforce safety policies:
429
+
430
+ ```python
431
+ from chuk_tool_processor.guards import (
432
+ GuardChain,
433
+ SchemaStrictnessGuard,
434
+ SensitiveDataGuard,
435
+ NetworkPolicyGuard,
436
+ ConcurrencyGuard,
437
+ )
438
+
439
+ # Create individual guards
440
+ schema_guard = SchemaStrictnessGuard(get_schema=my_schema_getter)
441
+ sensitive_guard = SensitiveDataGuard() # Detects API keys, JWTs, etc.
442
+ network_guard = NetworkPolicyGuard(block_private_ips=True)
443
+ concurrency_guard = ConcurrencyGuard(global_max=50, per_tool_max={"heavy_api": 2})
444
+
445
+ # Compose into a chain
446
+ chain = GuardChain([schema_guard, sensitive_guard, network_guard, concurrency_guard])
447
+
448
+ # Check before execution
449
+ result = await chain.check_all_async("api.fetch", {"url": "https://example.com"})
450
+ if result.blocked:
451
+ print(f"Blocked by {result.stopped_at}: {result.reason}")
452
+ ```
453
+
454
+ **Key Guards:**
455
+ - **SchemaStrictnessGuard** — Validate args against JSON schemas, auto-coerce types
456
+ - **SensitiveDataGuard** — Block or redact secrets (API keys, JWTs, private keys)
457
+ - **NetworkPolicyGuard** — SSRF defense (block localhost, private IPs, metadata endpoints)
458
+ - **SideEffectGuard** — Enforce read-only mode, block destructive ops in production
459
+ - **ConcurrencyGuard** — Limit in-flight calls globally, per-tool, or per-namespace
460
+ - **TimeoutBudgetGuard** — Enforce wall-clock budgets with soft/hard limits
461
+ - **OutputSizeGuard** — Prevent pathological payloads (size, depth, array length)
462
+ - **SaturationGuard** — Detect degenerate statistical outputs (extreme Z-scores, saturated CDFs)
463
+
464
+ See [GUARDS.md](docs/GUARDS.md) for complete documentation and examples.
465
+
466
+ ---
467
+
468
+ ## Dynamic Tool Discovery
469
+
470
+ When you have hundreds of tools, LLMs can't load all schemas upfront. The discovery module provides intelligent search and on-demand tool loading:
471
+
472
+ ```python
473
+ from chuk_tool_processor.discovery import ToolSearchEngine, BaseDynamicToolProvider
474
+
475
+ # Create a search engine for your tools
476
+ engine = ToolSearchEngine()
477
+ engine.set_tools(my_tools)
478
+
479
+ # Natural language search with synonym expansion
480
+ results = engine.search("gaussian distribution") # Finds "normal_cdf"
481
+ results = engine.search("find the average") # Finds "calculate_mean"
482
+ results = engine.search("multipley") # Finds "multiply" (typo tolerance)
483
+
484
+ # Session boosting - recently used tools rank higher
485
+ engine.record_tool_use("calculate_mean", success=True)
486
+ engine.advance_turn()
487
+ results = engine.search("calculate") # "calculate_mean" now boosted
488
+ ```
489
+
490
+ **Dynamic Provider Pattern** — give LLMs meta-tools for discovery:
491
+
492
+ ```python
493
+ class MyToolProvider(BaseDynamicToolProvider):
494
+ async def get_all_tools(self) -> list[Tool]:
495
+ return self._tools
496
+
497
+ async def execute_tool(self, name: str, args: dict) -> dict:
498
+ return await self._tools[name].execute(**args)
499
+
500
+ provider = MyToolProvider()
501
+
502
+ # LLM gets 4 meta-tools: list_tools, search_tools, get_tool_schema, call_tool
503
+ tools_for_llm = provider.get_dynamic_tools()
504
+
505
+ # LLM workflow: search → get schema → call
506
+ results = await provider.search_tools("calculate average")
507
+ schema = await provider.get_tool_schema("calculate_mean")
508
+ result = await provider.call_tool("calculate_mean", {"values": [1, 2, 3]})
509
+ ```
510
+
511
+ See [DISCOVERY.md](docs/DISCOVERY.md) for complete documentation.
512
+
513
+ ---
514
+
400
515
  ## Observability
401
516
 
402
517
  One-line setup for production monitoring:
@@ -454,6 +569,8 @@ See [ERRORS.md](docs/ERRORS.md) for complete error taxonomy.
454
569
  | [**GETTING_STARTED.md**](docs/GETTING_STARTED.md) | Creating tools, using the processor, ValidatedTool, StreamingTool |
455
570
  | [**CORE_CONCEPTS.md**](docs/CORE_CONCEPTS.md) | Registry, strategies, wrappers, parsers, MCP overview |
456
571
  | [**PRODUCTION_PATTERNS.md**](docs/PRODUCTION_PATTERNS.md) | Bulkheads, scoped registries, ExecutionContext, parallel execution |
572
+ | [**DISCOVERY.md**](docs/DISCOVERY.md) | Dynamic tool discovery, intelligent search, synonym expansion |
573
+ | [**GUARDS.md**](docs/GUARDS.md) | Runtime guards for safety, validation, and resource management |
457
574
  | [**MCP_INTEGRATION.md**](docs/MCP_INTEGRATION.md) | HTTP Streamable, STDIO, SSE, OAuth, Middleware Stack |
458
575
  | [**ADVANCED_TOPICS.md**](docs/ADVANCED_TOPICS.md) | Deferred loading, code sandbox, isolated strategy, testing |
459
576
  | [**CONFIGURATION.md**](docs/CONFIGURATION.md) | All config options and environment variables |
@@ -468,6 +585,9 @@ See [ERRORS.md](docs/ERRORS.md) for complete error taxonomy.
468
585
  # Getting started
469
586
  python examples/01_getting_started/hello_tool.py
470
587
 
588
+ # Dynamic tool discovery (search, synonyms, fuzzy matching)
589
+ python examples/07_discovery/dynamic_tools_demo.py
590
+
471
591
  # Hero demo: 8 tools, 5-second deadline, 3 pools (DAG + bulkheads + context)
472
592
  python examples/02_production_features/hero_runtime_demo.py
473
593
 
@@ -480,6 +600,9 @@ python examples/02_production_features/runtime_features_demo.py
480
600
  # Structured error handling for planners
481
601
  python examples/02_production_features/structured_errors_demo.py
482
602
 
603
+ # Runtime guards (validation, security, resource limits)
604
+ python examples/guards_demo.py
605
+
483
606
  # Redis registry for distributed deployments
484
607
  python examples/02_production_features/redis_registry_demo.py
485
608
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "chuk-tool-processor"
7
- version = "0.17"
7
+ version = "0.19"
8
8
  description = "Async-native framework for registering, discovering, and executing tools referenced in LLM responses"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -44,6 +44,20 @@ from chuk_tool_processor.core.context import (
44
44
  )
45
45
  from chuk_tool_processor.core.processor import ToolProcessor
46
46
 
47
+ # Discovery (tool search and dynamic providers)
48
+ from chuk_tool_processor.discovery import (
49
+ BaseDynamicToolProvider,
50
+ DynamicToolName,
51
+ SearchableTool,
52
+ SearchResult,
53
+ SessionToolStats,
54
+ ToolSearchEngine,
55
+ find_tool_by_alias,
56
+ find_tool_exact,
57
+ get_search_engine,
58
+ search_tools,
59
+ )
60
+
47
61
  # Execution strategies and bulkhead
48
62
  from chuk_tool_processor.execution.bulkhead import (
49
63
  Bulkhead,
@@ -56,6 +70,75 @@ from chuk_tool_processor.execution.strategies.inprocess_strategy import InProces
56
70
  from chuk_tool_processor.execution.strategies.subprocess_strategy import SubprocessStrategy
57
71
  from chuk_tool_processor.execution.strategies.subprocess_strategy import SubprocessStrategy as IsolatedStrategy
58
72
 
73
+ # Guards
74
+ from chuk_tool_processor.guards import (
75
+ BaseGuard,
76
+ BudgetGuard,
77
+ BudgetGuardConfig,
78
+ BudgetState,
79
+ BudgetStatus,
80
+ ConcurrencyConfig,
81
+ ConcurrencyGuard,
82
+ ConcurrencyLimitExceeded,
83
+ ConcurrencyState,
84
+ DegradeAction,
85
+ EnforcementLevel,
86
+ Environment,
87
+ ErrorClass,
88
+ ExecutionMode,
89
+ Guard,
90
+ GuardChain,
91
+ GuardChainResult,
92
+ GuardResult,
93
+ GuardVerdict,
94
+ NetworkPolicyConfig,
95
+ NetworkPolicyGuard,
96
+ NetworkViolation,
97
+ NetworkViolationType,
98
+ OutputSizeConfig,
99
+ OutputSizeGuard,
100
+ PerToolGuard,
101
+ PerToolGuardConfig,
102
+ PlanShapeConfig,
103
+ PlanShapeGuard,
104
+ PlanShapeState,
105
+ PlanShapeViolation,
106
+ PlanShapeViolationType,
107
+ PreconditionGuard,
108
+ PreconditionGuardConfig,
109
+ ProvenanceConfig,
110
+ ProvenanceGuard,
111
+ ProvenanceRecord,
112
+ RedactMode,
113
+ RetrySafetyConfig,
114
+ RetrySafetyGuard,
115
+ RetryState,
116
+ RunawayGuard,
117
+ RunawayGuardConfig,
118
+ SchemaStrictnessConfig,
119
+ SchemaStrictnessGuard,
120
+ SchemaValidationResult,
121
+ SchemaViolation,
122
+ SchemaViolationType,
123
+ SensitiveDataConfig,
124
+ SensitiveDataGuard,
125
+ SensitiveDataType,
126
+ SensitiveMatch,
127
+ SideEffectClass,
128
+ SideEffectConfig,
129
+ SideEffectGuard,
130
+ SizeViolation,
131
+ SizeViolationType,
132
+ TimeoutBudgetConfig,
133
+ TimeoutBudgetGuard,
134
+ TimeoutBudgetState,
135
+ ToolClassification,
136
+ TruncatedResult,
137
+ TruncationMode,
138
+ UnresolvedReferenceGuard,
139
+ UnresolvedReferenceGuardConfig,
140
+ )
141
+
59
142
  # MCP setup helpers
60
143
  from chuk_tool_processor.mcp import (
61
144
  setup_mcp_http_streamable,
@@ -165,6 +248,95 @@ __all__ = [
165
248
  "RegistryConfig",
166
249
  "ResilienceBackend",
167
250
  "create_executor",
251
+ # Guards - Base
252
+ "BaseGuard",
253
+ "Guard",
254
+ "GuardResult",
255
+ "GuardVerdict",
256
+ "EnforcementLevel",
257
+ "ToolClassification",
258
+ # Guards - Chain
259
+ "GuardChain",
260
+ "GuardChainResult",
261
+ # Guards - Original
262
+ "BudgetGuard",
263
+ "BudgetGuardConfig",
264
+ "BudgetState",
265
+ "PerToolGuard",
266
+ "PerToolGuardConfig",
267
+ "PreconditionGuard",
268
+ "PreconditionGuardConfig",
269
+ "RunawayGuard",
270
+ "RunawayGuardConfig",
271
+ "UnresolvedReferenceGuard",
272
+ "UnresolvedReferenceGuardConfig",
273
+ # Guards - Schema Strictness
274
+ "SchemaStrictnessGuard",
275
+ "SchemaStrictnessConfig",
276
+ "SchemaValidationResult",
277
+ "SchemaViolation",
278
+ "SchemaViolationType",
279
+ # Guards - Output Size
280
+ "OutputSizeGuard",
281
+ "OutputSizeConfig",
282
+ "SizeViolation",
283
+ "SizeViolationType",
284
+ "TruncatedResult",
285
+ "TruncationMode",
286
+ # Guards - Sensitive Data
287
+ "SensitiveDataGuard",
288
+ "SensitiveDataConfig",
289
+ "SensitiveDataType",
290
+ "SensitiveMatch",
291
+ "RedactMode",
292
+ # Guards - Concurrency
293
+ "ConcurrencyGuard",
294
+ "ConcurrencyConfig",
295
+ "ConcurrencyState",
296
+ "ConcurrencyLimitExceeded",
297
+ # Guards - Network Policy
298
+ "NetworkPolicyGuard",
299
+ "NetworkPolicyConfig",
300
+ "NetworkViolation",
301
+ "NetworkViolationType",
302
+ # Guards - Side Effect
303
+ "SideEffectGuard",
304
+ "SideEffectConfig",
305
+ "SideEffectClass",
306
+ "ExecutionMode",
307
+ "Environment",
308
+ # Guards - Timeout Budget
309
+ "TimeoutBudgetGuard",
310
+ "TimeoutBudgetConfig",
311
+ "TimeoutBudgetState",
312
+ "BudgetStatus",
313
+ "DegradeAction",
314
+ # Guards - Retry Safety
315
+ "RetrySafetyGuard",
316
+ "RetrySafetyConfig",
317
+ "RetryState",
318
+ "ErrorClass",
319
+ # Guards - Provenance
320
+ "ProvenanceGuard",
321
+ "ProvenanceConfig",
322
+ "ProvenanceRecord",
323
+ # Guards - Plan Shape
324
+ "PlanShapeGuard",
325
+ "PlanShapeConfig",
326
+ "PlanShapeState",
327
+ "PlanShapeViolation",
328
+ "PlanShapeViolationType",
329
+ # Discovery
330
+ "BaseDynamicToolProvider",
331
+ "DynamicToolName",
332
+ "ToolSearchEngine",
333
+ "SearchResult",
334
+ "SearchableTool",
335
+ "SessionToolStats",
336
+ "get_search_engine",
337
+ "search_tools",
338
+ "find_tool_exact",
339
+ "find_tool_by_alias",
168
340
  ]
169
341
 
170
342
  # Type checking exports (documentation only)
@@ -0,0 +1,77 @@
1
+ # chuk_tool_processor/discovery/__init__.py
2
+ """Tool discovery and search capabilities.
3
+
4
+ This module provides intelligent tool search with:
5
+ - Tokenized OR semantics (any matching keyword scores)
6
+ - Synonym expansion ("gaussian" finds "normal", "cdf" finds "cumulative")
7
+ - Fuzzy matching fallback for typos
8
+ - Namespace aliasing ("math.normal_cdf" finds "normal_cdf")
9
+ - Always returns results (fallback to popular tools)
10
+ - Session boosting (recently used tools rank higher)
11
+
12
+ It also provides a base class for dynamic tool providers that allow LLMs
13
+ to discover and execute tools on-demand.
14
+ """
15
+
16
+ from chuk_tool_processor.discovery.dynamic_provider import (
17
+ BaseDynamicToolProvider,
18
+ DynamicToolName,
19
+ )
20
+ from chuk_tool_processor.discovery.search import (
21
+ SearchResult,
22
+ SessionToolStats,
23
+ ToolSearchEngine,
24
+ extract_keywords,
25
+ find_tool_by_alias,
26
+ find_tool_exact,
27
+ fuzzy_score,
28
+ get_search_engine,
29
+ levenshtein_distance,
30
+ normalize_tool_name,
31
+ score_token_match,
32
+ search_tools,
33
+ tokenize,
34
+ )
35
+ from chuk_tool_processor.discovery.searchable import SearchableTool
36
+ from chuk_tool_processor.discovery.synonyms import (
37
+ DOMAIN_INDICATORS,
38
+ STOPWORDS,
39
+ SYNONYMS,
40
+ compute_domain_penalty,
41
+ detect_query_domain,
42
+ detect_tool_domain,
43
+ expand_with_synonyms,
44
+ )
45
+
46
+ __all__ = [
47
+ # Dynamic provider
48
+ "BaseDynamicToolProvider",
49
+ "DynamicToolName",
50
+ # Core search
51
+ "ToolSearchEngine",
52
+ "SearchResult",
53
+ "SessionToolStats",
54
+ "get_search_engine",
55
+ "search_tools",
56
+ "find_tool_exact",
57
+ # Protocol
58
+ "SearchableTool",
59
+ # Token processing
60
+ "tokenize",
61
+ "extract_keywords",
62
+ "expand_with_synonyms",
63
+ # Scoring
64
+ "score_token_match",
65
+ "fuzzy_score",
66
+ "levenshtein_distance",
67
+ # Name aliasing
68
+ "normalize_tool_name",
69
+ "find_tool_by_alias",
70
+ # Synonyms and domain detection
71
+ "SYNONYMS",
72
+ "DOMAIN_INDICATORS",
73
+ "STOPWORDS",
74
+ "detect_query_domain",
75
+ "detect_tool_domain",
76
+ "compute_domain_penalty",
77
+ ]