chuk-tool-processor 0.6__tar.gz → 0.6.1__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 (71) hide show
  1. chuk_tool_processor-0.6.1/PKG-INFO +693 -0
  2. chuk_tool_processor-0.6.1/README.md +670 -0
  3. chuk_tool_processor-0.6.1/pyproject.toml +65 -0
  4. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/strategies/inprocess_strategy.py +107 -8
  5. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/strategies/subprocess_strategy.py +110 -13
  6. chuk_tool_processor-0.6.1/src/chuk_tool_processor/mcp/mcp_tool.py +445 -0
  7. chuk_tool_processor-0.6.1/src/chuk_tool_processor/mcp/register_mcp_tools.py +147 -0
  8. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/stream_manager.py +319 -65
  9. chuk_tool_processor-0.6.1/src/chuk_tool_processor.egg-info/PKG-INFO +693 -0
  10. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor.egg-info/SOURCES.txt +0 -1
  11. chuk_tool_processor-0.6/PKG-INFO +0 -830
  12. chuk_tool_processor-0.6/README.md +0 -819
  13. chuk_tool_processor-0.6/pyproject.toml +0 -39
  14. chuk_tool_processor-0.6/src/chuk_tool_processor/mcp/mcp_tool.py +0 -243
  15. chuk_tool_processor-0.6/src/chuk_tool_processor/mcp/register_mcp_tools.py +0 -100
  16. chuk_tool_processor-0.6/src/chuk_tool_processor.egg-info/PKG-INFO +0 -830
  17. chuk_tool_processor-0.6/src/chuk_tool_processor.egg-info/requires.txt +0 -4
  18. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/setup.cfg +0 -0
  19. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/__init__.py +0 -0
  20. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/core/__init__.py +0 -0
  21. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/core/exceptions.py +0 -0
  22. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/core/processor.py +0 -0
  23. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/__init__.py +0 -0
  24. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/strategies/__init__.py +0 -0
  25. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/tool_executor.py +0 -0
  26. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/wrappers/__init__.py +0 -0
  27. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/wrappers/caching.py +0 -0
  28. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/wrappers/rate_limiting.py +0 -0
  29. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/execution/wrappers/retry.py +0 -0
  30. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/logging/__init__.py +0 -0
  31. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/logging/context.py +0 -0
  32. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/logging/formatter.py +0 -0
  33. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/logging/helpers.py +0 -0
  34. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/logging/metrics.py +0 -0
  35. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/__init__.py +0 -0
  36. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/setup_mcp_http_streamable.py +0 -0
  37. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/setup_mcp_sse.py +0 -0
  38. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/setup_mcp_stdio.py +0 -0
  39. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/transport/__init__.py +0 -0
  40. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/transport/base_transport.py +0 -0
  41. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/transport/http_streamable_transport.py +0 -0
  42. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/transport/sse_transport.py +0 -0
  43. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/mcp/transport/stdio_transport.py +0 -0
  44. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/__init__.py +0 -0
  45. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/execution_strategy.py +0 -0
  46. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/streaming_tool.py +0 -0
  47. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/tool_call.py +0 -0
  48. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/tool_export_mixin.py +0 -0
  49. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/tool_result.py +0 -0
  50. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/models/validated_tool.py +0 -0
  51. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/__init__.py +0 -0
  52. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/discovery.py +0 -0
  53. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/__init__.py +0 -0
  54. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/base.py +0 -0
  55. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/function_call_tool.py +0 -0
  56. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/json_tool.py +0 -0
  57. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/openai_tool.py +0 -0
  58. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/plugins/parsers/xml_tool.py +0 -0
  59. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/__init__.py +0 -0
  60. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/auto_register.py +0 -0
  61. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/decorators.py +0 -0
  62. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/interface.py +0 -0
  63. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/metadata.py +0 -0
  64. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/provider.py +0 -0
  65. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/providers/__init__.py +0 -0
  66. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/providers/memory.py +0 -0
  67. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/registry/tool_export.py +0 -0
  68. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/utils/__init__.py +0 -0
  69. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor/utils/validation.py +0 -0
  70. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor.egg-info/dependency_links.txt +0 -0
  71. {chuk_tool_processor-0.6 → chuk_tool_processor-0.6.1}/src/chuk_tool_processor.egg-info/top_level.txt +0 -0
@@ -0,0 +1,693 @@
1
+ Metadata-Version: 2.4
2
+ Name: chuk-tool-processor
3
+ Version: 0.6.1
4
+ Summary: Async-native framework for registering, discovering, and executing tools referenced in LLM responses
5
+ Author-email: CHUK Team <chrishayuk@somejunkmailbox.com>
6
+ Maintainer-email: CHUK Team <chrishayuk@somejunkmailbox.com>
7
+ License: MIT
8
+ Keywords: llm,tools,async,ai,openai,mcp,model-context-protocol,tool-calling,function-calling
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Framework :: AsyncIO
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+
24
+ # CHUK Tool Processor - Architectural Analysis
25
+
26
+ ## Overview
27
+ The CHUK Tool Processor is a sophisticated async-native framework for registering, discovering, and executing tools referenced in LLM responses. Built from the ground up for production use with comprehensive error handling, monitoring, and scalability features. It features a modular architecture with multiple transport mechanisms, execution strategies, and comprehensive tooling for production use.
28
+
29
+ ## Quick Start Example
30
+ ```python
31
+ import asyncio
32
+ from chuk_tool_processor import ToolProcessor, register_tool, initialize
33
+
34
+ # 1. Create a tool
35
+ @register_tool(name="calculator", description="Perform basic math operations")
36
+ class Calculator:
37
+ async def execute(self, operation: str, a: float, b: float) -> dict:
38
+ operations = {
39
+ "add": a + b,
40
+ "subtract": a - b,
41
+ "multiply": a * b,
42
+ "divide": a / b if b != 0 else None
43
+ }
44
+
45
+ if operation not in operations:
46
+ raise ValueError(f"Unknown operation: {operation}")
47
+
48
+ result = operations[operation]
49
+ if result is None:
50
+ raise ValueError("Cannot divide by zero")
51
+
52
+ return {"operation": operation, "operands": [a, b], "result": result}
53
+
54
+ async def main():
55
+ # 2. Initialize the system
56
+ await initialize()
57
+
58
+ # 3. Process LLM output containing tool calls
59
+ processor = ToolProcessor()
60
+ results = await processor.process('''
61
+ <tool name="calculator" args='{"operation": "multiply", "a": 15, "b": 23}'/>
62
+ ''')
63
+
64
+ # 4. Handle results
65
+ for result in results:
66
+ if result.error:
67
+ print(f"❌ Tool '{result.tool}' failed: {result.error}")
68
+ else:
69
+ print(f"✅ Tool '{result.tool}' result: {result.result}")
70
+
71
+ asyncio.run(main())
72
+ ```
73
+
74
+ ## Key Features & Benefits
75
+
76
+ - **🔄 Async-Native**: Built for `async/await` from the ground up for optimal performance
77
+ - **🛡️ Production Ready**: Comprehensive error handling, timeouts, retries, and monitoring
78
+ - **📦 Multiple Execution Strategies**: In-process for speed, subprocess for isolation
79
+ - **🚀 High Performance**: Built-in caching, rate limiting, and concurrency control
80
+ - **📊 Observability**: Structured logging, metrics collection, and request tracing
81
+ - **🔗 MCP Integration**: Full Model Context Protocol support (STDIO, SSE, HTTP Streamable)
82
+ - **📡 Streaming Support**: Real-time incremental results for long-running operations
83
+ - **🔧 Extensible Architecture**: Plugin system for custom parsers and execution strategies
84
+ - **🎯 Multiple Input Formats**: XML tags, OpenAI tool_calls, JSON, function_call formats
85
+ - **⚡ Zero-Config Start**: Works out of the box with sensible defaults
86
+
87
+ ## Core Architecture
88
+
89
+ ### Installation & Setup
90
+
91
+ ```bash
92
+ # From source (recommended for development)
93
+ git clone https://github.com/chrishayuk/chuk-tool-processor.git
94
+ cd chuk-tool-processor
95
+ pip install -e .
96
+
97
+ # Or install from PyPI (when available)
98
+ pip install chuk-tool-processor
99
+ ```
100
+
101
+ ### Environment Configuration
102
+ ```bash
103
+ # Optional: Registry provider (default: memory)
104
+ export CHUK_TOOL_REGISTRY_PROVIDER=memory
105
+
106
+ # Optional: Default timeout (default: 30.0)
107
+ export CHUK_DEFAULT_TIMEOUT=30.0
108
+
109
+ # Optional: Enable structured JSON logging
110
+ export CHUK_STRUCTURED_LOGGING=true
111
+
112
+ # MCP Integration (if using external MCP servers)
113
+ export MCP_BEARER_TOKEN=your_bearer_token_here
114
+ ```
115
+ ### 1. Registry System
116
+ - **Interface-driven**: `ToolRegistryInterface` protocol defines the contract
117
+ - **Async-native**: All registry operations are async
118
+ - **Namespace support**: Tools are organized into namespaces (default: "default")
119
+ - **Metadata tracking**: Rich metadata with `ToolMetadata` model
120
+ - **Provider pattern**: `ToolRegistryProvider` for singleton management
121
+
122
+ ```python
123
+ # Example registry usage
124
+ registry = await ToolRegistryProvider.get_registry()
125
+ await registry.register_tool(MyTool(), name="my_tool", namespace="custom")
126
+ tool = await registry.get_tool("my_tool", "custom")
127
+ ```
128
+
129
+ ### 2. Tool Development Patterns
130
+
131
+ #### Simple Function-Based Tools
132
+ ```python
133
+ from chuk_tool_processor.registry.auto_register import register_fn_tool
134
+
135
+ async def get_current_time(timezone: str = "UTC") -> str:
136
+ """Get the current time in the specified timezone."""
137
+ from datetime import datetime
138
+ import pytz
139
+
140
+ tz = pytz.timezone(timezone)
141
+ current_time = datetime.now(tz)
142
+ return current_time.strftime("%Y-%m-%d %H:%M:%S %Z")
143
+
144
+ # Register the function as a tool
145
+ await register_fn_tool(get_current_time, namespace="utilities")
146
+ ```
147
+
148
+ #### ValidatedTool (Declarative with Pydantic)
149
+ ```python
150
+ @register_tool(name="weather", namespace="api")
151
+ class WeatherTool(ValidatedTool):
152
+ class Arguments(BaseModel):
153
+ location: str = Field(..., description="City name or coordinates")
154
+ units: str = Field("metric", description="Temperature units")
155
+
156
+ class Result(BaseModel):
157
+ location: str
158
+ temperature: float
159
+ conditions: str
160
+
161
+ async def _execute(self, location: str, units: str) -> Result:
162
+ # Implementation here
163
+ return self.Result(location=location, temperature=22.5, conditions="Sunny")
164
+ ```
165
+
166
+ #### StreamingTool (Real-time Results)
167
+ ```python
168
+ @register_tool(name="file_processor")
169
+ class FileProcessorTool(StreamingTool):
170
+ class Arguments(BaseModel):
171
+ file_path: str
172
+ operation: str = "count_lines"
173
+
174
+ class Result(BaseModel):
175
+ line_number: int
176
+ content: str
177
+
178
+ async def _stream_execute(self, file_path: str, operation: str):
179
+ """Stream results as each line is processed."""
180
+ for i in range(1, 100):
181
+ await asyncio.sleep(0.01) # Simulate processing
182
+ yield self.Result(line_number=i, content=f"Processed line {i}")
183
+ ```
184
+
185
+ ### 3. Processing LLM Responses
186
+
187
+ The processor automatically detects and parses multiple input formats:
188
+
189
+ ```python
190
+ processor = ToolProcessor()
191
+
192
+ # 1. XML Tool Tags (most common)
193
+ xml_response = """
194
+ <tool name="search" args='{"query": "Python programming", "limit": 5}'/>
195
+ <tool name="get_current_time" args='{"timezone": "UTC"}'/>
196
+ """
197
+
198
+ # 2. OpenAI Chat Completions Format
199
+ openai_response = {
200
+ "tool_calls": [
201
+ {
202
+ "id": "call_123",
203
+ "type": "function",
204
+ "function": {
205
+ "name": "search",
206
+ "arguments": '{"query": "Python programming", "limit": 5}'
207
+ }
208
+ }
209
+ ]
210
+ }
211
+
212
+ # 3. Direct ToolCall objects
213
+ tool_calls = [
214
+ {"tool": "search", "arguments": {"query": "Python programming", "limit": 5}},
215
+ {"tool": "get_current_time", "arguments": {"timezone": "UTC"}}
216
+ ]
217
+
218
+ # Process any format
219
+ results1 = await processor.process(xml_response)
220
+ results2 = await processor.process(openai_response)
221
+ results3 = await processor.process(tool_calls)
222
+ ```
223
+
224
+ ### 4. Execution Strategies
225
+
226
+ #### InProcessStrategy (Default - Fast & Efficient)
227
+ - **Concurrent execution**: Uses asyncio for parallelism within the same process
228
+ - **Semaphore-based limiting**: Optional max_concurrency control
229
+ - **True streaming support**: Direct access to `stream_execute` methods
230
+ - **Enhanced tool resolution**: Namespace fallback logic with fuzzy matching
231
+ - **Proper timeout handling**: Always applies concrete timeouts
232
+
233
+ #### SubprocessStrategy (Isolation & Safety)
234
+ - **Process isolation**: Each tool runs in separate OS process for safety
235
+ - **Serialization support**: Handles complex objects and Pydantic models properly
236
+ - **Worker pool management**: Concurrent futures with automatic cleanup
237
+ - **Enhanced error handling**: Broken pool recovery and restart
238
+ - **Timeout coordination**: Safety timeouts prevent worker hangs
239
+
240
+ ```python
241
+ # Configure execution strategy
242
+ from chuk_tool_processor.execution.strategies.subprocess_strategy import SubprocessStrategy
243
+
244
+ processor = ToolProcessor(
245
+ strategy=SubprocessStrategy(
246
+ registry=await get_default_registry(),
247
+ max_workers=4,
248
+ default_timeout=30.0
249
+ )
250
+ )
251
+ ```
252
+
253
+ ### 5. Production Features & Wrappers
254
+
255
+ #### Caching for Performance
256
+ ```python
257
+ from chuk_tool_processor.execution.wrappers.caching import cacheable
258
+
259
+ @cacheable(ttl=600) # Cache for 10 minutes
260
+ @register_tool(name="expensive_api")
261
+ class ExpensiveApiTool(ValidatedTool):
262
+ # Tool implementation
263
+ pass
264
+
265
+ # Or configure at processor level
266
+ processor = ToolProcessor(
267
+ enable_caching=True,
268
+ cache_ttl=300 # 5 minutes default
269
+ )
270
+ ```
271
+
272
+ #### Rate Limiting
273
+ ```python
274
+ from chuk_tool_processor.execution.wrappers.rate_limiting import rate_limited
275
+
276
+ @rate_limited(limit=20, period=60.0) # 20 calls per minute
277
+ @register_tool(name="api_tool")
278
+ class ApiTool(ValidatedTool):
279
+ # Tool implementation
280
+ pass
281
+
282
+ # Or processor-level configuration
283
+ processor = ToolProcessor(
284
+ enable_rate_limiting=True,
285
+ global_rate_limit=100, # 100 requests per minute globally
286
+ tool_rate_limits={
287
+ "expensive_api": (10, 60), # 10 per minute for specific tool
288
+ }
289
+ )
290
+ ```
291
+
292
+ #### Automatic Retries
293
+ ```python
294
+ from chuk_tool_processor.execution.wrappers.retry import retryable
295
+
296
+ @retryable(max_retries=3, base_delay=1.0)
297
+ @register_tool(name="unreliable_api")
298
+ class UnreliableApiTool(ValidatedTool):
299
+ # Tool implementation
300
+ pass
301
+
302
+ # Processor-level retry configuration
303
+ processor = ToolProcessor(
304
+ enable_retries=True,
305
+ max_retries=3
306
+ )
307
+ ```
308
+
309
+ ### 6. MCP (Model Context Protocol) Integration
310
+
311
+ Connect to external tool servers using multiple transport protocols:
312
+
313
+ #### Quick MCP Setup with SSE (Server-Sent Events)
314
+ ```python
315
+ from chuk_tool_processor.mcp import setup_mcp_sse
316
+
317
+ # Configure external MCP servers
318
+ servers = [
319
+ {
320
+ "name": "weather-service",
321
+ "url": "https://weather-mcp.example.com",
322
+ "api_key": "your_weather_api_key"
323
+ },
324
+ {
325
+ "name": "database-service",
326
+ "url": "https://db-mcp.example.com",
327
+ "api_key": "your_db_api_key"
328
+ }
329
+ ]
330
+
331
+ # Initialize with full production configuration
332
+ processor, stream_manager = await setup_mcp_sse(
333
+ servers=servers,
334
+ namespace="mcp", # Tools available as mcp.tool_name
335
+ default_timeout=30.0,
336
+ enable_caching=True,
337
+ enable_retries=True
338
+ )
339
+
340
+ # Use external tools through MCP
341
+ results = await processor.process('''
342
+ <tool name="mcp.weather" args='{"location": "London"}'/>
343
+ <tool name="mcp.database_query" args='{"sql": "SELECT COUNT(*) FROM users"}'/>
344
+ ''')
345
+ ```
346
+
347
+ #### STDIO Transport (Process-based)
348
+ ```python
349
+ from chuk_tool_processor.mcp import setup_mcp_stdio
350
+
351
+ # Create MCP config for local processes
352
+ mcp_config = {
353
+ "weather": {
354
+ "command": "python",
355
+ "args": ["-m", "weather_mcp_server"],
356
+ "env": {"API_KEY": "your_weather_key"}
357
+ }
358
+ }
359
+
360
+ processor, stream_manager = await setup_mcp_stdio(
361
+ config_file="mcp_config.json",
362
+ servers=["weather"],
363
+ namespace="tools"
364
+ )
365
+ ```
366
+
367
+ #### Supported Transports
368
+ - **STDIO**: Process-based communication for local MCP servers
369
+ - **SSE**: Server-Sent Events for cloud-based MCP services
370
+ - **HTTP Streamable**: Modern HTTP-based transport (spec 2025-03-26)
371
+
372
+ ### 7. Monitoring & Observability
373
+
374
+ #### Structured Logging
375
+ ```python
376
+ from chuk_tool_processor.logging import setup_logging, get_logger, log_context_span
377
+
378
+ # Setup structured logging
379
+ await setup_logging(
380
+ level=logging.INFO,
381
+ structured=True, # JSON output for production
382
+ log_file="tool_processor.log"
383
+ )
384
+
385
+ # Use contextual logging
386
+ logger = get_logger("my_app")
387
+
388
+ async def process_user_request(user_id: str, request: str):
389
+ async with log_context_span("user_request", {"user_id": user_id}):
390
+ logger.info("Processing user request", extra={
391
+ "request_length": len(request),
392
+ "user_id": user_id
393
+ })
394
+
395
+ results = await processor.process(request)
396
+
397
+ logger.info("Request processed successfully", extra={
398
+ "num_tools": len(results),
399
+ "success_rate": sum(1 for r in results if not r.error) / len(results)
400
+ })
401
+ ```
402
+
403
+ #### Automatic Metrics Collection
404
+ ```python
405
+ # Metrics are automatically collected for:
406
+ # - Tool execution success/failure rates
407
+ # - Execution durations and performance
408
+ # - Cache hit/miss rates and efficiency
409
+ # - Parser performance and accuracy
410
+ # - Registry operations and health
411
+
412
+ # Access programmatic metrics
413
+ from chuk_tool_processor.logging import metrics
414
+
415
+ # Custom metrics
416
+ await metrics.log_tool_execution(
417
+ tool="custom_metric",
418
+ success=True,
419
+ duration=1.5,
420
+ cached=False,
421
+ attempts=1
422
+ )
423
+ ```
424
+
425
+ ### 8. Error Handling & Best Practices
426
+
427
+ #### Robust Error Handling
428
+ ```python
429
+ async def robust_tool_processing(llm_response: str):
430
+ """Example of production-ready error handling."""
431
+ processor = ToolProcessor(
432
+ default_timeout=30.0,
433
+ enable_retries=True,
434
+ max_retries=3
435
+ )
436
+
437
+ try:
438
+ results = await processor.process(llm_response, timeout=60.0)
439
+
440
+ successful_results = []
441
+ failed_results = []
442
+
443
+ for result in results:
444
+ if result.error:
445
+ failed_results.append(result)
446
+ logger.error(f"Tool {result.tool} failed: {result.error}", extra={
447
+ "tool": result.tool,
448
+ "duration": result.duration,
449
+ "attempts": getattr(result, "attempts", 1)
450
+ })
451
+ else:
452
+ successful_results.append(result)
453
+ logger.info(f"Tool {result.tool} succeeded", extra={
454
+ "tool": result.tool,
455
+ "duration": result.duration,
456
+ "cached": getattr(result, "cached", False)
457
+ })
458
+
459
+ return {
460
+ "successful": successful_results,
461
+ "failed": failed_results,
462
+ "success_rate": len(successful_results) / len(results) if results else 0
463
+ }
464
+
465
+ except Exception as e:
466
+ logger.exception("Failed to process LLM response")
467
+ raise
468
+ ```
469
+
470
+ #### Testing Your Tools
471
+ ```python
472
+ import pytest
473
+ from chuk_tool_processor import ToolProcessor, initialize
474
+
475
+ @pytest.mark.asyncio
476
+ async def test_calculator_tool():
477
+ await initialize()
478
+ processor = ToolProcessor()
479
+
480
+ results = await processor.process(
481
+ '<tool name="calculator" args=\'{"operation": "add", "a": 5, "b": 3}\'/>'
482
+ )
483
+
484
+ assert len(results) == 1
485
+ result = results[0]
486
+ assert result.error is None
487
+ assert result.result["result"] == 8
488
+ ```
489
+
490
+ ## Advanced Configuration
491
+
492
+ ### Production-Ready Setup
493
+ ```python
494
+ from chuk_tool_processor import ToolProcessor
495
+ from chuk_tool_processor.execution.strategies.subprocess_strategy import SubprocessStrategy
496
+
497
+ async def create_production_processor():
498
+ """Configure processor for high-throughput production use."""
499
+
500
+ processor = ToolProcessor(
501
+ # Execution settings
502
+ default_timeout=30.0,
503
+ max_concurrency=20, # Allow 20 concurrent executions
504
+
505
+ # Use subprocess strategy for isolation
506
+ strategy=SubprocessStrategy(
507
+ registry=await get_default_registry(),
508
+ max_workers=8, # 8 worker processes
509
+ default_timeout=30.0
510
+ ),
511
+
512
+ # Performance optimizations
513
+ enable_caching=True,
514
+ cache_ttl=900, # 15-minute cache
515
+
516
+ # Rate limiting to prevent abuse
517
+ enable_rate_limiting=True,
518
+ global_rate_limit=500, # 500 requests per minute globally
519
+ tool_rate_limits={
520
+ "expensive_api": (10, 60), # 10 per minute
521
+ "file_processor": (5, 60), # 5 per minute
522
+ },
523
+
524
+ # Reliability features
525
+ enable_retries=True,
526
+ max_retries=3,
527
+
528
+ # Input parsing
529
+ parser_plugins=["xml_tool", "openai_tool", "json_tool"]
530
+ )
531
+
532
+ await processor.initialize()
533
+ return processor
534
+ ```
535
+
536
+ ### Performance Optimization
537
+ ```python
538
+ # Concurrent batch processing
539
+ async def process_batch(requests: list[str]):
540
+ """Process multiple LLM responses concurrently."""
541
+ processor = await create_production_processor()
542
+
543
+ tasks = [processor.process(request) for request in requests]
544
+ all_results = await asyncio.gather(*tasks, return_exceptions=True)
545
+
546
+ successful = []
547
+ failed = []
548
+
549
+ for i, result in enumerate(all_results):
550
+ if isinstance(result, Exception):
551
+ failed.append({"request_index": i, "error": str(result)})
552
+ else:
553
+ successful.append({"request_index": i, "results": result})
554
+
555
+ return {"successful": successful, "failed": failed}
556
+
557
+ # Memory management for long-running applications
558
+ async def maintenance_task():
559
+ """Periodic maintenance for production deployments."""
560
+ while True:
561
+ await asyncio.sleep(3600) # Every hour
562
+
563
+ # Clear old cache entries
564
+ if hasattr(processor.executor, 'cache'):
565
+ await processor.executor.cache.clear()
566
+ logger.info("Cache cleared for memory management")
567
+ ```
568
+
569
+ ## Key Design Patterns
570
+
571
+ 1. **Async-First Design**: All core operations use async/await with proper timeout handling, graceful cancellation support, and comprehensive resource cleanup via context managers.
572
+
573
+ 2. **Strategy Pattern**: Pluggable execution strategies (InProcess vs Subprocess), composable wrapper chains, and interface-driven design for maximum flexibility.
574
+
575
+ 3. **Registry Pattern**: Centralized tool management with namespace isolation, rich metadata tracking, and lazy initialization for optimal resource usage.
576
+
577
+ 4. **Plugin Architecture**: Discoverable parsers for different input formats, transport abstractions for MCP integration, and extensible validation systems.
578
+
579
+ 5. **Producer-Consumer**: Queue-based streaming architecture for real-time results, with proper backpressure handling and timeout coordination.
580
+
581
+ 6. **Decorator Pattern**: Composable execution wrappers (caching, retries, rate limiting) that can be stacked and configured independently.
582
+
583
+ ## Configuration Reference
584
+
585
+ ### Environment Variables
586
+ | Variable | Default | Description |
587
+ |----------|---------|-------------|
588
+ | `CHUK_TOOL_REGISTRY_PROVIDER` | `memory` | Registry backend (memory, redis, etc.) |
589
+ | `CHUK_DEFAULT_TIMEOUT` | `30.0` | Default tool execution timeout (seconds) |
590
+ | `CHUK_LOG_LEVEL` | `INFO` | Logging level (DEBUG, INFO, WARNING, ERROR) |
591
+ | `CHUK_STRUCTURED_LOGGING` | `true` | Enable JSON structured logging |
592
+ | `CHUK_MAX_CONCURRENCY` | `10` | Default max concurrent executions |
593
+ | `MCP_BEARER_TOKEN` | - | Bearer token for MCP SSE authentication |
594
+
595
+ ### ToolProcessor Options
596
+ ```python
597
+ processor = ToolProcessor(
598
+ # Core execution
599
+ default_timeout=30.0, # Default timeout per tool
600
+ max_concurrency=10, # Max concurrent executions
601
+
602
+ # Strategy selection
603
+ strategy=InProcessStrategy(...), # Fast, shared memory
604
+ # strategy=SubprocessStrategy(...), # Isolated, safer for untrusted code
605
+
606
+ # Performance features
607
+ enable_caching=True, # Result caching
608
+ cache_ttl=300, # Cache TTL in seconds
609
+ enable_rate_limiting=False, # Rate limiting
610
+ enable_retries=True, # Automatic retries
611
+ max_retries=3, # Max retry attempts
612
+
613
+ # Input processing
614
+ parser_plugins=["xml_tool", "openai_tool", "json_tool"]
615
+ )
616
+ ```
617
+
618
+ ## Why Choose CHUK Tool Processor?
619
+
620
+ ### Built for Production
621
+ - **Battle-tested**: Comprehensive error handling, timeout management, and resource cleanup
622
+ - **Scalable**: Support for high-throughput concurrent execution with configurable limits
623
+ - **Observable**: Built-in structured logging, metrics collection, and request tracing
624
+ - **Reliable**: Automatic retries, circuit breakers, and graceful degradation
625
+
626
+ ### Developer Experience
627
+ - **Zero-config start**: Works out of the box with sensible defaults
628
+ - **Type-safe**: Full Pydantic integration for argument and result validation
629
+ - **Multiple paradigms**: Support for functions, classes, and streaming tools
630
+ - **Flexible inputs**: Handles XML tags, OpenAI format, JSON, and direct objects
631
+
632
+ ### Enterprise Ready
633
+ - **Process isolation**: Subprocess strategy for running untrusted code safely
634
+ - **Rate limiting**: Global and per-tool rate limiting with sliding window algorithm
635
+ - **Caching layer**: Intelligent caching with TTL and invalidation strategies
636
+ - **MCP integration**: Connect to external tool servers using industry standards
637
+
638
+ ### Performance Optimized
639
+ - **Async-native**: Built from ground up for `async/await` with proper concurrency
640
+ - **Streaming support**: Real-time incremental results for long-running operations
641
+ - **Resource efficient**: Lazy initialization, connection pooling, and memory management
642
+ - **Configurable strategies**: Choose between speed (in-process) and safety (subprocess)
643
+
644
+ ## Getting Started
645
+
646
+ ### 1. Installation
647
+ ```bash
648
+ # From source (recommended for development)
649
+ git clone https://github.com/chrishayuk/chuk-tool-processor.git
650
+ cd chuk-tool-processor
651
+ pip install -e .
652
+
653
+ # Or install from PyPI (when available)
654
+ pip install chuk-tool-processor
655
+ ```
656
+
657
+ ### 2. Quick Example
658
+ ```python
659
+ import asyncio
660
+ from chuk_tool_processor import ToolProcessor, register_tool, initialize
661
+
662
+ @register_tool(name="hello")
663
+ class HelloTool:
664
+ async def execute(self, name: str) -> str:
665
+ return f"Hello, {name}!"
666
+
667
+ async def main():
668
+ await initialize()
669
+ processor = ToolProcessor()
670
+
671
+ results = await processor.process(
672
+ '<tool name="hello" args=\'{"name": "World"}\'/>'
673
+ )
674
+
675
+ print(results[0].result) # Output: Hello, World!
676
+
677
+ asyncio.run(main())
678
+ ```
679
+
680
+ ### 3. Next Steps
681
+ - Review the [Architecture Guide](docs/architecture.md) for deeper understanding
682
+ - Check out [Tool Development Guide](docs/tools.md) for advanced patterns
683
+ - Explore [MCP Integration](docs/mcp.md) for external tool servers
684
+ - See [Production Deployment](docs/deployment.md) for scaling considerations
685
+
686
+ ## Contributing & Support
687
+
688
+ - **GitHub**: [chrishayuk/chuk-tool-processor](https://github.com/chrishayuk/chuk-tool-processor)
689
+ - **Issues**: [Report bugs and request features](https://github.com/chrishayuk/chuk-tool-processor/issues)
690
+ - **Discussions**: [Community discussions](https://github.com/chrishayuk/chuk-tool-processor/discussions)
691
+ - **License**: MIT - see [LICENSE](LICENSE) file for details
692
+
693
+ Built with ❤️ by the CHUK AI team for the LLM tool integration community.