chuk-tool-processor 0.1.6__py3-none-any.whl → 0.1.7__py3-none-any.whl

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.

Potentially problematic release.


This version of chuk-tool-processor might be problematic. Click here for more details.

Files changed (45) hide show
  1. chuk_tool_processor/core/processor.py +345 -132
  2. chuk_tool_processor/execution/strategies/inprocess_strategy.py +512 -68
  3. chuk_tool_processor/execution/strategies/subprocess_strategy.py +523 -63
  4. chuk_tool_processor/execution/tool_executor.py +282 -24
  5. chuk_tool_processor/execution/wrappers/caching.py +465 -123
  6. chuk_tool_processor/execution/wrappers/rate_limiting.py +199 -86
  7. chuk_tool_processor/execution/wrappers/retry.py +133 -23
  8. chuk_tool_processor/logging/__init__.py +83 -10
  9. chuk_tool_processor/logging/context.py +218 -22
  10. chuk_tool_processor/logging/formatter.py +56 -13
  11. chuk_tool_processor/logging/helpers.py +91 -16
  12. chuk_tool_processor/logging/metrics.py +75 -6
  13. chuk_tool_processor/mcp/mcp_tool.py +80 -35
  14. chuk_tool_processor/mcp/register_mcp_tools.py +74 -56
  15. chuk_tool_processor/mcp/setup_mcp_sse.py +41 -36
  16. chuk_tool_processor/mcp/setup_mcp_stdio.py +39 -37
  17. chuk_tool_processor/models/execution_strategy.py +52 -3
  18. chuk_tool_processor/models/streaming_tool.py +110 -0
  19. chuk_tool_processor/models/tool_call.py +56 -4
  20. chuk_tool_processor/models/tool_result.py +115 -9
  21. chuk_tool_processor/models/validated_tool.py +15 -13
  22. chuk_tool_processor/plugins/discovery.py +115 -70
  23. chuk_tool_processor/plugins/parsers/base.py +13 -5
  24. chuk_tool_processor/plugins/parsers/{function_call_tool_plugin.py → function_call_tool.py} +39 -20
  25. chuk_tool_processor/plugins/parsers/json_tool.py +50 -0
  26. chuk_tool_processor/plugins/parsers/openai_tool.py +88 -0
  27. chuk_tool_processor/plugins/parsers/xml_tool.py +74 -20
  28. chuk_tool_processor/registry/__init__.py +46 -7
  29. chuk_tool_processor/registry/auto_register.py +92 -28
  30. chuk_tool_processor/registry/decorators.py +134 -11
  31. chuk_tool_processor/registry/interface.py +48 -14
  32. chuk_tool_processor/registry/metadata.py +52 -6
  33. chuk_tool_processor/registry/provider.py +75 -36
  34. chuk_tool_processor/registry/providers/__init__.py +49 -10
  35. chuk_tool_processor/registry/providers/memory.py +59 -48
  36. chuk_tool_processor/registry/tool_export.py +208 -39
  37. chuk_tool_processor/utils/validation.py +18 -13
  38. chuk_tool_processor-0.1.7.dist-info/METADATA +401 -0
  39. chuk_tool_processor-0.1.7.dist-info/RECORD +58 -0
  40. {chuk_tool_processor-0.1.6.dist-info → chuk_tool_processor-0.1.7.dist-info}/WHEEL +1 -1
  41. chuk_tool_processor/plugins/parsers/json_tool_plugin.py +0 -38
  42. chuk_tool_processor/plugins/parsers/openai_tool_plugin.py +0 -76
  43. chuk_tool_processor-0.1.6.dist-info/METADATA +0 -462
  44. chuk_tool_processor-0.1.6.dist-info/RECORD +0 -57
  45. {chuk_tool_processor-0.1.6.dist-info → chuk_tool_processor-0.1.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,401 @@
1
+ Metadata-Version: 2.4
2
+ Name: chuk-tool-processor
3
+ Version: 0.1.7
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: chuk-mcp>=0.1.12
8
+ Requires-Dist: dotenv>=0.9.9
9
+ Requires-Dist: openai>=1.76.0
10
+ Requires-Dist: pydantic>=2.11.3
11
+ Requires-Dist: uuid>=1.30
12
+
13
+ # CHUK Tool Processor
14
+
15
+ An async-native framework for registering, discovering, and executing tools referenced in LLM responses.
16
+
17
+ ## Quick Start
18
+
19
+ ### Installation
20
+
21
+ ```bash
22
+ # Clone the repository
23
+ git clone https://github.com/your-org/chuk-tool-processor.git
24
+ cd chuk-tool-processor
25
+
26
+ # Install with pip
27
+ pip install -e .
28
+ ```
29
+
30
+ ### Basic Usage
31
+
32
+ ```python
33
+ import asyncio
34
+ from chuk_tool_processor.registry import register_tool, initialize
35
+ from chuk_tool_processor.models.tool_call import ToolCall
36
+ from chuk_tool_processor.execution.strategies.inprocess_strategy import InProcessStrategy
37
+ from chuk_tool_processor.execution.tool_executor import ToolExecutor
38
+
39
+ # Register a simple tool
40
+ @register_tool(name="calculator", description="Perform basic calculations")
41
+ class CalculatorTool:
42
+ async def execute(self, operation: str, x: float, y: float) -> dict:
43
+ if operation == "add":
44
+ result = x + y
45
+ elif operation == "multiply":
46
+ result = x * y
47
+ else:
48
+ raise ValueError(f"Unknown operation: {operation}")
49
+
50
+ return {
51
+ "operation": operation,
52
+ "x": x,
53
+ "y": y,
54
+ "result": result
55
+ }
56
+
57
+ # Setup and execute tools
58
+ async def main():
59
+ # Initialize registry
60
+ await initialize()
61
+
62
+ # Get the default registry
63
+ from chuk_tool_processor.registry import get_default_registry
64
+ registry = await get_default_registry()
65
+
66
+ # Create execution strategy and executor
67
+ strategy = InProcessStrategy(registry)
68
+ executor = ToolExecutor(registry=registry, strategy=strategy)
69
+
70
+ # Create a tool call
71
+ call = ToolCall(
72
+ tool="calculator",
73
+ arguments={
74
+ "operation": "multiply",
75
+ "x": 5,
76
+ "y": 7
77
+ }
78
+ )
79
+
80
+ # Execute tool
81
+ results = await executor.execute([call])
82
+
83
+ # Display result
84
+ result = results[0]
85
+ if not result.error:
86
+ print(f"Result: {result.result}")
87
+ else:
88
+ print(f"Error: {result.error}")
89
+
90
+ if __name__ == "__main__":
91
+ asyncio.run(main())
92
+ ```
93
+
94
+ ## Core Features
95
+
96
+ ### Async-Native Architecture
97
+
98
+ The entire framework is built with native `async/await` support, allowing for:
99
+ - Non-blocking execution of tools
100
+ - True concurrency with controlled parallelism
101
+ - Task-local context tracking across async boundaries
102
+
103
+ ### Tool Registry
104
+
105
+ Tools are registered in a central registry with optional namespaces:
106
+
107
+ ```python
108
+ # Register with default parameters
109
+ @register_tool()
110
+ class SimpleGreeter:
111
+ async def execute(self, name: str) -> str:
112
+ return f"Hello, {name}!"
113
+
114
+ # Register with custom name and namespace
115
+ @register_tool(name="weather", namespace="api", description="Get weather info")
116
+ class WeatherTool:
117
+ async def execute(self, location: str, units: str = "metric") -> dict:
118
+ # Implementation...
119
+ return {"temperature": 23.5, "conditions": "Sunny"}
120
+ ```
121
+
122
+ Initialize and access the registry:
123
+
124
+ ```python
125
+ # Initialize registry (required at startup)
126
+ await initialize()
127
+
128
+ # Get registry
129
+ registry = await get_default_registry()
130
+
131
+ # Look up a tool
132
+ tool = await registry.get_tool("weather", namespace="api")
133
+
134
+ # List registered tools
135
+ tools = await registry.list_tools()
136
+
137
+ # Get tool metadata
138
+ metadata = await registry.get_metadata("weather", namespace="api")
139
+ ```
140
+
141
+ ### Execution Strategies
142
+
143
+ Two execution strategies are provided:
144
+
145
+ #### 1. InProcessStrategy
146
+
147
+ Executes tools in the same process with optional concurrency control:
148
+
149
+ ```python
150
+ from chuk_tool_processor.execution.strategies.inprocess_strategy import InProcessStrategy
151
+
152
+ strategy = InProcessStrategy(
153
+ registry,
154
+ default_timeout=10.0, # Timeout for tool execution
155
+ max_concurrency=5 # Maximum concurrent executions
156
+ )
157
+ ```
158
+
159
+ #### 2. SubprocessStrategy
160
+
161
+ Executes tools in separate processes for true isolation:
162
+
163
+ ```python
164
+ from chuk_tool_processor.execution.strategies.subprocess_strategy import SubprocessStrategy
165
+
166
+ strategy = SubprocessStrategy(
167
+ registry,
168
+ max_workers=4, # Maximum worker processes
169
+ default_timeout=30.0 # Timeout for tool execution
170
+ )
171
+ ```
172
+
173
+ ### Execution Wrappers
174
+
175
+ Enhance tool execution with optional wrappers:
176
+
177
+ #### Retry Logic
178
+
179
+ ```python
180
+ from chuk_tool_processor.execution.wrappers.retry import RetryConfig, RetryableToolExecutor
181
+
182
+ # Use as a wrapper
183
+ retry_executor = RetryableToolExecutor(
184
+ executor=base_executor,
185
+ default_config=RetryConfig(
186
+ max_retries=3,
187
+ base_delay=0.5,
188
+ jitter=True
189
+ )
190
+ )
191
+
192
+ # Or as a decorator
193
+ from chuk_tool_processor.execution.wrappers.retry import retryable
194
+
195
+ @retryable(max_retries=3, base_delay=0.5)
196
+ @register_tool(name="flaky_api")
197
+ class FlakyApiTool:
198
+ async def execute(self, query: str) -> dict:
199
+ # Implementation with potential failures
200
+ pass
201
+ ```
202
+
203
+ #### Caching
204
+
205
+ ```python
206
+ from chuk_tool_processor.execution.wrappers.caching import InMemoryCache, CachingToolExecutor
207
+
208
+ # Use as a wrapper
209
+ cache = InMemoryCache(default_ttl=60) # 60 second TTL
210
+ cache_executor = CachingToolExecutor(
211
+ executor=base_executor,
212
+ cache=cache
213
+ )
214
+
215
+ # Or as a decorator
216
+ from chuk_tool_processor.execution.wrappers.caching import cacheable
217
+
218
+ @cacheable(ttl=300) # Cache for 5 minutes
219
+ @register_tool(name="expensive_operation")
220
+ class ExpensiveOperationTool:
221
+ async def execute(self, input_value: int) -> dict:
222
+ # Expensive computation
223
+ pass
224
+ ```
225
+
226
+ #### Rate Limiting
227
+
228
+ ```python
229
+ from chuk_tool_processor.execution.wrappers.rate_limiting import RateLimiter, RateLimitedToolExecutor
230
+
231
+ # Use as a wrapper
232
+ limiter = RateLimiter(global_limit=100, global_period=60.0) # 100 requests per minute
233
+ rate_limited_executor = RateLimitedToolExecutor(
234
+ executor=base_executor,
235
+ limiter=limiter
236
+ )
237
+
238
+ # Or as a decorator
239
+ from chuk_tool_processor.execution.wrappers.rate_limiting import rate_limited
240
+
241
+ @rate_limited(limit=5, period=60.0) # 5 requests per minute
242
+ @register_tool(name="external_api")
243
+ class ExternalApiTool:
244
+ async def execute(self, query: str) -> dict:
245
+ # Call to rate-limited external API
246
+ pass
247
+ ```
248
+
249
+ ### Streaming Tool Support
250
+
251
+ Tools can stream results incrementally:
252
+
253
+ ```python
254
+ from chuk_tool_processor.models.streaming_tool import StreamingTool
255
+ from pydantic import BaseModel, Field
256
+ from typing import AsyncIterator
257
+
258
+ @register_tool(name="counter")
259
+ class CounterTool(StreamingTool):
260
+ """Stream incremental counts."""
261
+
262
+ class Arguments(BaseModel):
263
+ start: int = Field(1, description="Starting value")
264
+ end: int = Field(10, description="Ending value")
265
+ delay: float = Field(0.5, description="Delay between items")
266
+
267
+ class Result(BaseModel):
268
+ value: int
269
+ timestamp: str
270
+
271
+ async def _stream_execute(self, start: int, end: int, delay: float) -> AsyncIterator[Result]:
272
+ """Stream each count with a delay."""
273
+ from datetime import datetime
274
+
275
+ for i in range(start, end + 1):
276
+ await asyncio.sleep(delay)
277
+ yield self.Result(
278
+ value=i,
279
+ timestamp=datetime.now().isoformat()
280
+ )
281
+
282
+ # Stream results
283
+ async for result in executor.stream_execute([tool_call]):
284
+ print(f"Received: {result.result.value}")
285
+ ```
286
+
287
+ ### Comprehensive Error Handling
288
+
289
+ Errors are captured in the result objects rather than raising exceptions:
290
+
291
+ ```python
292
+ # Execute tool calls
293
+ results = await executor.execute([call1, call2, call3])
294
+
295
+ for result in results:
296
+ if result.error:
297
+ print(f"Tool {result.tool} failed: {result.error}")
298
+ print(f"Duration: {(result.end_time - result.start_time).total_seconds()}s")
299
+ else:
300
+ print(f"Tool {result.tool} succeeded: {result.result}")
301
+ ```
302
+
303
+ ### Validation
304
+
305
+ Validate tool arguments and results:
306
+
307
+ ```python
308
+ from pydantic import BaseModel
309
+ from chuk_tool_processor.models.validated_tool import ValidatedTool
310
+
311
+ @register_tool(name="validate_data", namespace="utils")
312
+ class ValidatedDataTool(ValidatedTool):
313
+ class Arguments(BaseModel):
314
+ username: str
315
+ age: int
316
+ email: str
317
+
318
+ class Result(BaseModel):
319
+ is_valid: bool
320
+ errors: list[str] = []
321
+
322
+ async def _execute(self, username: str, age: int, email: str) -> Result:
323
+ errors = []
324
+
325
+ if len(username) < 3:
326
+ errors.append("Username too short")
327
+
328
+ if age < 18:
329
+ errors.append("Must be 18 or older")
330
+
331
+ if "@" not in email:
332
+ errors.append("Invalid email")
333
+
334
+ return self.Result(
335
+ is_valid=len(errors) == 0,
336
+ errors=errors
337
+ )
338
+ ```
339
+
340
+ ## Processing LLM Responses
341
+
342
+ The `ToolProcessor` helps extract and execute tool calls from LLM responses:
343
+
344
+ ```python
345
+ from chuk_tool_processor.core.processor import ToolProcessor
346
+
347
+ # Create processor
348
+ processor = ToolProcessor()
349
+ await processor.initialize()
350
+
351
+ # Process text with tool calls
352
+ llm_output = """
353
+ I'll help calculate that for you.
354
+
355
+ <tool name="calculator" args='{"operation": "multiply", "x": 5, "y": 7}'/>
356
+
357
+ The result should be 35.
358
+ """
359
+
360
+ # Extract and execute tool calls
361
+ results = await processor.process_text(llm_output)
362
+
363
+ # Process results
364
+ for result in results:
365
+ print(f"Tool: {result.tool}")
366
+ print(f"Result: {result.result}")
367
+ print(f"Error: {result.error}")
368
+ ```
369
+
370
+ The processor supports various formats:
371
+
372
+ ```python
373
+ # XML format
374
+ <tool name="calculator" args='{"operation": "add", "x": 5, "y": 3}'/>
375
+
376
+ # OpenAI function call format
377
+ {
378
+ "function_call": {
379
+ "name": "calculator",
380
+ "arguments": "{\"operation\": \"add\", \"x\": 5, \"y\": 3}"
381
+ }
382
+ }
383
+
384
+ # JSON format
385
+ {
386
+ "tool_calls": [
387
+ {
388
+ "id": "call_123",
389
+ "type": "function",
390
+ "function": {
391
+ "name": "calculator",
392
+ "arguments": "{\"operation\": \"add\", \"x\": 5, \"y\": 3}"
393
+ }
394
+ }
395
+ ]
396
+ }
397
+ ```
398
+
399
+ ## License
400
+
401
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -0,0 +1,58 @@
1
+ chuk_tool_processor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ chuk_tool_processor/core/__init__.py,sha256=slM7pZna88tyZrF3KtN22ApYyCqGNt5Yscv-knsLOOA,38
3
+ chuk_tool_processor/core/exceptions.py,sha256=h4zL1jpCY1Ud1wT8xDeMxZ8GR8ttmkObcv36peUHJEA,1571
4
+ chuk_tool_processor/core/processor.py,sha256=ttEYZTQHctXXiUP8gxAMCCSjbRvyOHojQe_UJezJYRs,18369
5
+ chuk_tool_processor/execution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ chuk_tool_processor/execution/tool_executor.py,sha256=NSzmvqGMMyKuVapJAmPr-YtNgGhZI3fcAxhilyGG5kY,12174
7
+ chuk_tool_processor/execution/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ chuk_tool_processor/execution/strategies/inprocess_strategy.py,sha256=7Vx8zZ10DSK73tfinahAHElprctIJ1f4WKaR8lJf_Jk,21710
9
+ chuk_tool_processor/execution/strategies/subprocess_strategy.py,sha256=6ByvqHhZ5fenrV7yPNRUHeid-htTiVu05Gn0n6ImXg4,20477
10
+ chuk_tool_processor/execution/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ chuk_tool_processor/execution/wrappers/caching.py,sha256=1pSyouYT4H7AGkNcK_7wWAIT1d4AKnHJlKBODPO8tZw,20416
12
+ chuk_tool_processor/execution/wrappers/rate_limiting.py,sha256=CBBsI1VLosjo8dZXLeJ3IaclGvy9VdjGyqgunY089KQ,9231
13
+ chuk_tool_processor/execution/wrappers/retry.py,sha256=oK6g0Ey8zbAubOgOvDbTFyvP1bVCI53knjXgfd_b3dw,10350
14
+ chuk_tool_processor/logging/__init__.py,sha256=Uux0QnL6Xcd4vNjtt54rNei3yvxUZ-sOuAahlcPAez0,3382
15
+ chuk_tool_processor/logging/context.py,sha256=8wLE6yoDxush7rGu_wTzVCautqq-Jq_0R9SBxLOjpwI,8520
16
+ chuk_tool_processor/logging/formatter.py,sha256=RhlV6NqBYRBOtytDY49c9Y1J4l02ZjNXIgVRn03tfSQ,3061
17
+ chuk_tool_processor/logging/helpers.py,sha256=c1mS1sb_rh4bKG0hisyvT7l7cirQfXPSyWeBqmqALRw,5941
18
+ chuk_tool_processor/logging/metrics.py,sha256=s59Au8q0eqGGtJMDqmJBZhbJHh4BWGE1CzT0iI8lRS8,3624
19
+ chuk_tool_processor/mcp/__init__.py,sha256=vR9HHxLpXlKTIIwJJRr3QTmZegcdedR1YKyb46j6FIM,689
20
+ chuk_tool_processor/mcp/mcp_tool.py,sha256=BcFsW0iVXUpE0o-h3u2hYX-88EmfV80nMUoZPyZs_IY,3242
21
+ chuk_tool_processor/mcp/register_mcp_tools.py,sha256=0q73gafC1d0ei_gqNidcUeY7NUg13UZdjhVOKEFcD5o,3642
22
+ chuk_tool_processor/mcp/setup_mcp_sse.py,sha256=FmXyOG9DuH2pzr1TLTFRFLlW23YkFG8rzSdpybtPCJg,2865
23
+ chuk_tool_processor/mcp/setup_mcp_stdio.py,sha256=P9qSgmxoNQbsOlGp83DlLLpN9BsG__MhlRsxFplNP3M,2753
24
+ chuk_tool_processor/mcp/stream_manager.py,sha256=mrmlG54P_xLbDYz_rBjdu-OPMnbi916dgyJg7BrIbjM,12798
25
+ chuk_tool_processor/mcp/transport/__init__.py,sha256=7QQqeSKVKv0N9GcyJuYF0R4FDZeooii5RjggvFFg5GY,296
26
+ chuk_tool_processor/mcp/transport/base_transport.py,sha256=1E29LjWw5vLQrPUDF_9TJt63P5dxAAN7n6E_KiZbGUY,3427
27
+ chuk_tool_processor/mcp/transport/sse_transport.py,sha256=bryH9DOWOn5qr6LsimTriukDC4ix2kuRq6bUv9qOV20,7645
28
+ chuk_tool_processor/mcp/transport/stdio_transport.py,sha256=lFXL7p8ca4z_J0RBL8UCHrQ1UH7C2-LbC0tZhpya4V4,7763
29
+ chuk_tool_processor/models/__init__.py,sha256=TC__rdVa0lQsmJHM_hbLDPRgToa_pQT_UxRcPZk6iVw,40
30
+ chuk_tool_processor/models/execution_strategy.py,sha256=UVW35YIeMY2B3mpIKZD2rAkyOPayI6ckOOUALyf0YiQ,2115
31
+ chuk_tool_processor/models/streaming_tool.py,sha256=0v2PSPTgZ5TS_PpVdohvVhh99fPwPQM_R_z4RU0mlLM,3541
32
+ chuk_tool_processor/models/tool_call.py,sha256=t3QOQVzUaNRBea_n5fsrCgK4_ILiZlT8LvF7UwaZU84,1748
33
+ chuk_tool_processor/models/tool_export_mixin.py,sha256=U9NJvn9fqH3pW50ozdDAHlA0fQSnjUt-lYhEoW_leZU,998
34
+ chuk_tool_processor/models/tool_result.py,sha256=-8LdlaE9Ajfb1t-UyN9lW0XB2abQWALD7j8PZc-txhQ,5029
35
+ chuk_tool_processor/models/validated_tool.py,sha256=LYc9-IBCiQmoMUotyByinRQQ-jfrC6g6tflMtSf9MUg,5908
36
+ chuk_tool_processor/plugins/__init__.py,sha256=QO_ipvlsWG-rbaqGzj6-YtD7zi7Lx26hw-Cqha4MuWc,48
37
+ chuk_tool_processor/plugins/discovery.py,sha256=kHRpOrcRnHiviKHCCdQN04cpSUqbifAZdSbU81Wc0fA,7112
38
+ chuk_tool_processor/plugins/parsers/__init__.py,sha256=07waNfAGuytn-Dntx2IxjhgSkM9F40TBYNUXC8G4VVo,49
39
+ chuk_tool_processor/plugins/parsers/base.py,sha256=r-15AZUmlGwWC3EQHRxiqPgivNv-mro6aTKqOwhuAtg,752
40
+ chuk_tool_processor/plugins/parsers/function_call_tool.py,sha256=kaUTMhIpDP4jZa_CJZiGchIoszK3AboZM2BJOXzPJmg,3198
41
+ chuk_tool_processor/plugins/parsers/json_tool.py,sha256=jljG7jR9070oHSTFqcrXbtFjYorw1cb4ZpwfrsLgFSE,1556
42
+ chuk_tool_processor/plugins/parsers/openai_tool.py,sha256=O33DyXN0Llqv7AHygE9sVQkbSDVNIOcNqqa1CaZF6vo,2849
43
+ chuk_tool_processor/plugins/parsers/xml_tool.py,sha256=V-JSWWy1ncXwX6-Of45zaLEGXryjKMTDEgTmEl6-XlY,3186
44
+ chuk_tool_processor/registry/__init__.py,sha256=PBv5QyzHmUJEjgFQW1zgcUmppa5xUTjXTLVsYoVnDQI,2036
45
+ chuk_tool_processor/registry/auto_register.py,sha256=wanaibx9CNsI1et0v2I25xzi5I_w8YaSlvW05ENEpIU,7252
46
+ chuk_tool_processor/registry/decorators.py,sha256=qFK-z7wd53BY7rEbqqWMrWQXbP4UaTLVTCQRI2iUhHI,5035
47
+ chuk_tool_processor/registry/interface.py,sha256=dqThCnHd2KCgX8j96j_hZxF2rigGClrI-hRc5n_nv2M,3467
48
+ chuk_tool_processor/registry/metadata.py,sha256=lR9FO__lhPr-ax7PhFk8Se1bJdN_48rabiN7qegx4Ns,4582
49
+ chuk_tool_processor/registry/provider.py,sha256=YUCGCFARNxnzV2Dm72Ur4DOrDs_ZYDtCzd6OBBzlis8,5162
50
+ chuk_tool_processor/registry/tool_export.py,sha256=FEdMsfZ3uhiOjoDHqcnSwNehAN7Z5mgi4nI1UKu2hgs,7569
51
+ chuk_tool_processor/registry/providers/__init__.py,sha256=eigwG_So11j7WbDGSWaKd3KwVen3Rap-aNQCSWA6T4k,2705
52
+ chuk_tool_processor/registry/providers/memory.py,sha256=LlpPUU9E7S8Se6Q3VyKxLwpNm82SvmP8GLUmI8MkHxQ,5188
53
+ chuk_tool_processor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ chuk_tool_processor/utils/validation.py,sha256=fiTSsHq7zx-kyd755GaFCvPCa-EVasSpg0A1liNHkxU,4138
55
+ chuk_tool_processor-0.1.7.dist-info/METADATA,sha256=vqD7WCOAdv5CWGyQv0Hyp3oxWKGDkslRby84vVdCvLw,10165
56
+ chuk_tool_processor-0.1.7.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
57
+ chuk_tool_processor-0.1.7.dist-info/top_level.txt,sha256=7lTsnuRx4cOW4U2sNJWNxl4ZTt_J1ndkjTbj3pHPY5M,20
58
+ chuk_tool_processor-0.1.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,38 +0,0 @@
1
- # chuk_tool_processor/parsers/json_tool.py
2
- """JSON *tool_calls* parser plugin (drop-in).
3
-
4
- Accepts raw‐string or dict input where the top-level object includes a
5
- ``tool_calls`` array – an early OpenAI Chat Completions schema.
6
- """
7
- from __future__ import annotations
8
-
9
- import json
10
- from typing import Any, List
11
- from pydantic import ValidationError
12
-
13
- # imports
14
- from .base import ParserPlugin
15
- from chuk_tool_processor.models.tool_call import ToolCall
16
-
17
- class JsonToolPlugin(ParserPlugin):
18
- """Extracts ``tool_calls`` array from a JSON response."""
19
-
20
- def try_parse(self, raw: str | Any) -> List[ToolCall]:
21
- try:
22
- data = json.loads(raw) if isinstance(raw, str) else raw
23
- except json.JSONDecodeError:
24
- return []
25
-
26
- if not isinstance(data, dict):
27
- return []
28
-
29
- calls = data.get("tool_calls", [])
30
- out: List[ToolCall] = []
31
-
32
- for c in calls:
33
- try:
34
- out.append(ToolCall(**c))
35
- except ValidationError:
36
- continue
37
- return out
38
-
@@ -1,76 +0,0 @@
1
- # chuk_tool_processor/parsers/openai_tool_plugin.py
2
- """
3
- Parser for OpenAI Chat-Completions responses that contain a `tool_calls` array.
4
- """
5
-
6
- from __future__ import annotations
7
-
8
- import json
9
- from typing import Any, List
10
-
11
- from pydantic import ValidationError
12
-
13
- from .base import ParserPlugin
14
- from chuk_tool_processor.models.tool_call import ToolCall
15
-
16
-
17
- class OpenAIToolPlugin(ParserPlugin):
18
- """
19
- Understands responses that look like:
20
-
21
- {
22
- "tool_calls": [
23
- {
24
- "id": "call_abc",
25
- "type": "function",
26
- "function": {
27
- "name": "weather",
28
- "arguments": "{\"location\": \"New York\"}"
29
- }
30
- },
31
-
32
- ]
33
- }
34
- """
35
-
36
- def try_parse(self, raw: str | Any) -> List[ToolCall]:
37
- # ------------------------------------------------------------------ #
38
- # Parse the incoming JSON (string or already-dict)
39
- # ------------------------------------------------------------------ #
40
- try:
41
- data = json.loads(raw) if isinstance(raw, str) else raw
42
- except (TypeError, json.JSONDecodeError):
43
- return []
44
-
45
- if not isinstance(data, dict) or "tool_calls" not in data:
46
- return []
47
-
48
- # ------------------------------------------------------------------ #
49
- # Convert each entry into a ToolCall
50
- # ------------------------------------------------------------------ #
51
- calls: List[ToolCall] = []
52
- for tc in data["tool_calls"]:
53
- fn = tc.get("function", {})
54
- name = fn.get("name")
55
- args = fn.get("arguments", {})
56
-
57
- if not isinstance(name, str) or not name:
58
- continue
59
-
60
- # arguments come back as a JSON-encoded string – decode if needed
61
- if isinstance(args, str):
62
- try:
63
- args = json.loads(args)
64
- except json.JSONDecodeError:
65
- args = {}
66
-
67
- if not isinstance(args, dict):
68
- args = {}
69
-
70
- try:
71
- # `tool` must match the **registry key** (e.g. "weather")
72
- calls.append(ToolCall(tool=name, arguments=args))
73
- except ValidationError:
74
- continue # skip malformed entries
75
-
76
- return calls