chuk-tool-processor 0.1.0__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.
- chuk_tool_processor/__init__.py +1 -0
- chuk_tool_processor/core/__init__.py +1 -0
- chuk_tool_processor/core/exceptions.py +45 -0
- chuk_tool_processor/core/processor.py +268 -0
- chuk_tool_processor/execution/__init__.py +0 -0
- chuk_tool_processor/execution/strategies/__init__.py +0 -0
- chuk_tool_processor/execution/strategies/inprocess_strategy.py +206 -0
- chuk_tool_processor/execution/strategies/subprocess_strategy.py +103 -0
- chuk_tool_processor/execution/tool_executor.py +46 -0
- chuk_tool_processor/execution/wrappers/__init__.py +0 -0
- chuk_tool_processor/execution/wrappers/caching.py +234 -0
- chuk_tool_processor/execution/wrappers/rate_limiting.py +149 -0
- chuk_tool_processor/execution/wrappers/retry.py +176 -0
- chuk_tool_processor/models/__init__.py +1 -0
- chuk_tool_processor/models/execution_strategy.py +19 -0
- chuk_tool_processor/models/tool_call.py +7 -0
- chuk_tool_processor/models/tool_result.py +49 -0
- chuk_tool_processor/plugins/__init__.py +1 -0
- chuk_tool_processor/plugins/discovery.py +205 -0
- chuk_tool_processor/plugins/parsers/__init__.py +1 -0
- chuk_tool_processor/plugins/parsers/function_call_tool.py +105 -0
- chuk_tool_processor/plugins/parsers/json_tool.py +17 -0
- chuk_tool_processor/plugins/parsers/xml_tool.py +41 -0
- chuk_tool_processor/registry/__init__.py +20 -0
- chuk_tool_processor/registry/decorators.py +42 -0
- chuk_tool_processor/registry/interface.py +79 -0
- chuk_tool_processor/registry/metadata.py +36 -0
- chuk_tool_processor/registry/provider.py +44 -0
- chuk_tool_processor/registry/providers/__init__.py +41 -0
- chuk_tool_processor/registry/providers/memory.py +165 -0
- chuk_tool_processor/utils/__init__.py +0 -0
- chuk_tool_processor/utils/logging.py +260 -0
- chuk_tool_processor/utils/validation.py +192 -0
- chuk_tool_processor-0.1.0.dist-info/METADATA +293 -0
- chuk_tool_processor-0.1.0.dist-info/RECORD +37 -0
- chuk_tool_processor-0.1.0.dist-info/WHEEL +5 -0
- chuk_tool_processor-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chuk-tool-processor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: pydantic>=2.11.3
|
|
8
|
+
|
|
9
|
+
# CHUK Tool Processor
|
|
10
|
+
|
|
11
|
+
A robust framework for detecting, executing, and managing tool calls in LLM responses.
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
The CHUK Tool Processor is a Python library designed to handle the execution of tools referenced in the output of Large Language Models (LLMs). It provides a flexible and extensible architecture for:
|
|
16
|
+
|
|
17
|
+
1. **Parsing tool calls** from different formats (JSON, XML, function calls)
|
|
18
|
+
2. **Executing tools** with proper isolation and error handling
|
|
19
|
+
3. **Managing tool executions** with retry logic, caching, and rate limiting
|
|
20
|
+
4. **Monitoring tool usage** with comprehensive logging
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Multiple Parser Support**: Extract tool calls from JSON, XML, or OpenAI-style function call formats
|
|
25
|
+
- **Flexible Execution Strategies**: Choose between in-process or subprocess execution for different isolation needs
|
|
26
|
+
- **Namespace Support**: Organize tools in logical namespaces
|
|
27
|
+
- **Concurrency Control**: Set limits on parallel tool executions
|
|
28
|
+
- **Validation**: Type validation for tool arguments and results
|
|
29
|
+
- **Caching**: Cache tool results to improve performance for repeated calls
|
|
30
|
+
- **Rate Limiting**: Prevent overloading external services with configurable rate limits
|
|
31
|
+
- **Retry Logic**: Automatically retry transient failures with exponential backoff
|
|
32
|
+
- **Structured Logging**: Comprehensive logging system for debugging and monitoring
|
|
33
|
+
- **Plugin Discovery**: Dynamically discover and load plugins from packages
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Clone the repository
|
|
39
|
+
git clone https://github.com/your-org/chuk-tool-processor.git
|
|
40
|
+
cd chuk-tool-processor
|
|
41
|
+
|
|
42
|
+
# Install with pip
|
|
43
|
+
pip install -e .
|
|
44
|
+
|
|
45
|
+
# Or with uv
|
|
46
|
+
uv pip install -e .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
### Registering Tools
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from chuk_tool_processor.registry import register_tool
|
|
55
|
+
|
|
56
|
+
@register_tool(name="calculator", namespace="math")
|
|
57
|
+
class CalculatorTool:
|
|
58
|
+
def execute(self, operation: str, a: float, b: float):
|
|
59
|
+
if operation == "add":
|
|
60
|
+
return a + b
|
|
61
|
+
elif operation == "multiply":
|
|
62
|
+
return a * b
|
|
63
|
+
# ... other operations
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Processing Tool Calls
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import asyncio
|
|
70
|
+
from chuk_tool_processor.core.processor import ToolProcessor
|
|
71
|
+
|
|
72
|
+
async def main():
|
|
73
|
+
# Create a processor with default settings
|
|
74
|
+
processor = ToolProcessor()
|
|
75
|
+
|
|
76
|
+
# Process text with potential tool calls
|
|
77
|
+
llm_response = """
|
|
78
|
+
To calculate that, I'll use the calculator tool.
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
"function_call": {
|
|
82
|
+
"name": "calculator",
|
|
83
|
+
"arguments": {"operation": "multiply", "a": 123.45, "b": 67.89}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
results = await processor.process_text(llm_response)
|
|
89
|
+
|
|
90
|
+
# Handle results
|
|
91
|
+
for result in results:
|
|
92
|
+
print(f"Tool: {result.tool}")
|
|
93
|
+
print(f"Result: {result.result}")
|
|
94
|
+
print(f"Error: {result.error}")
|
|
95
|
+
print(f"Duration: {(result.end_time - result.start_time).total_seconds()}s")
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
asyncio.run(main())
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Advanced Usage
|
|
102
|
+
|
|
103
|
+
### Using Decorators for Tool Configuration
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from chuk_tool_processor.registry import register_tool
|
|
107
|
+
from chuk_tool_processor.utils.validation import with_validation
|
|
108
|
+
from chuk_tool_processor.execution.wrappers.retry import retryable
|
|
109
|
+
from chuk_tool_processor.execution.wrappers.caching import cacheable
|
|
110
|
+
from chuk_tool_processor.execution.wrappers.rate_limiting import rate_limited
|
|
111
|
+
from typing import Dict, Any, Optional
|
|
112
|
+
|
|
113
|
+
@register_tool(name="weather", namespace="data")
|
|
114
|
+
@retryable(max_retries=3)
|
|
115
|
+
@cacheable(ttl=3600) # Cache for 1 hour
|
|
116
|
+
@rate_limited(limit=100, period=60.0) # 100 requests per minute
|
|
117
|
+
@with_validation
|
|
118
|
+
class WeatherTool:
|
|
119
|
+
def execute(self, location: str, units: str = "metric") -> Dict[str, Any]:
|
|
120
|
+
# Implementation that calls a weather API
|
|
121
|
+
return {
|
|
122
|
+
"temperature": 22.5,
|
|
123
|
+
"conditions": "Partly Cloudy",
|
|
124
|
+
"humidity": 65
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Using Validated Tool Base Class
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from chuk_tool_processor.utils.validation import ValidatedTool
|
|
132
|
+
from chuk_tool_processor.registry import register_tool
|
|
133
|
+
from pydantic import BaseModel
|
|
134
|
+
from typing import Optional
|
|
135
|
+
|
|
136
|
+
@register_tool(namespace="data")
|
|
137
|
+
class WeatherTool(ValidatedTool):
|
|
138
|
+
class Arguments(BaseModel):
|
|
139
|
+
location: str
|
|
140
|
+
units: str = "metric" # Default to metric
|
|
141
|
+
|
|
142
|
+
class Result(BaseModel):
|
|
143
|
+
temperature: float
|
|
144
|
+
conditions: str
|
|
145
|
+
humidity: Optional[int] = None
|
|
146
|
+
|
|
147
|
+
def _execute(self, location: str, units: str = "metric"):
|
|
148
|
+
# Implementation
|
|
149
|
+
return {
|
|
150
|
+
"temperature": 22.5,
|
|
151
|
+
"conditions": "Sunny",
|
|
152
|
+
"humidity": 65
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Custom Execution Strategy
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from chuk_tool_processor.registry.providers.memory import InMemoryToolRegistry
|
|
160
|
+
from chuk_tool_processor.execution.tool_executor import ToolExecutor
|
|
161
|
+
from chuk_tool_processor.execution.inprocess_strategy import InProcessStrategy
|
|
162
|
+
|
|
163
|
+
# Create registry and register tools
|
|
164
|
+
registry = InMemoryToolRegistry()
|
|
165
|
+
registry.register_tool(MyTool(), name="my_tool")
|
|
166
|
+
|
|
167
|
+
# Create executor with custom strategy
|
|
168
|
+
executor = ToolExecutor(
|
|
169
|
+
registry,
|
|
170
|
+
strategy=InProcessStrategy(
|
|
171
|
+
registry,
|
|
172
|
+
default_timeout=5.0,
|
|
173
|
+
max_concurrency=10
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Execute tool calls
|
|
178
|
+
results = await executor.execute([call1, call2])
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Custom Parser Plugins
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from chuk_tool_processor.models.tool_call import ToolCall
|
|
185
|
+
from chuk_tool_processor.plugins.discovery import plugin_registry
|
|
186
|
+
import re
|
|
187
|
+
from typing import List
|
|
188
|
+
|
|
189
|
+
# Create a custom parser for a bracket syntax
|
|
190
|
+
class BracketToolParser:
|
|
191
|
+
"""Parser for [tool:name arg1=val1 arg2="val2"] syntax"""
|
|
192
|
+
|
|
193
|
+
def try_parse(self, raw: str) -> List[ToolCall]:
|
|
194
|
+
calls = []
|
|
195
|
+
# Regex to match [tool:name arg1=val1 arg2="val2"]
|
|
196
|
+
pattern = r"\[tool:([^\s\]]+)([^\]]*)\]"
|
|
197
|
+
matches = re.finditer(pattern, raw)
|
|
198
|
+
|
|
199
|
+
for match in matches:
|
|
200
|
+
tool_name = match.group(1)
|
|
201
|
+
args_str = match.group(2).strip()
|
|
202
|
+
|
|
203
|
+
# Parse arguments
|
|
204
|
+
args = {}
|
|
205
|
+
if args_str:
|
|
206
|
+
# Match key=value pairs, handling quoted values
|
|
207
|
+
args_pattern = r'([^\s=]+)=(?:([^\s"]+)|"([^"]*)")'
|
|
208
|
+
for arg_match in re.finditer(args_pattern, args_str):
|
|
209
|
+
key = arg_match.group(1)
|
|
210
|
+
# Either group 2 (unquoted) or group 3 (quoted)
|
|
211
|
+
value = arg_match.group(2) if arg_match.group(2) else arg_match.group(3)
|
|
212
|
+
args[key] = value
|
|
213
|
+
|
|
214
|
+
calls.append(ToolCall(tool=tool_name, arguments=args))
|
|
215
|
+
|
|
216
|
+
return calls
|
|
217
|
+
|
|
218
|
+
# Register plugin manually
|
|
219
|
+
plugin_registry.register_plugin("parser", "BracketToolParser", BracketToolParser())
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Structured Logging
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from chuk_tool_processor.utils.logging import get_logger, log_context_span
|
|
226
|
+
|
|
227
|
+
logger = get_logger("my_module")
|
|
228
|
+
|
|
229
|
+
# Create a context span for timing operations
|
|
230
|
+
with log_context_span("operation_name", {"extra": "context"}):
|
|
231
|
+
logger.info("Starting operation")
|
|
232
|
+
# Do something
|
|
233
|
+
logger.info("Operation completed")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Architecture
|
|
237
|
+
|
|
238
|
+
The tool processor has several key components organized into a modular structure:
|
|
239
|
+
|
|
240
|
+
1. **Registry**: Stores tool implementations and metadata
|
|
241
|
+
- `registry/interface.py`: Defines the registry interface
|
|
242
|
+
- `registry/providers/memory.py`: In-memory implementation
|
|
243
|
+
- `registry/providers/redis.py`: Redis-backed implementation
|
|
244
|
+
|
|
245
|
+
2. **Models**: Core data structures
|
|
246
|
+
- `models/tool_call.py`: Represents a tool call from an LLM
|
|
247
|
+
- `models/tool_result.py`: Represents the result of a tool execution
|
|
248
|
+
|
|
249
|
+
3. **Execution**: Tool execution strategies and wrappers
|
|
250
|
+
- `execution/tool_executor.py`: Main executor interface
|
|
251
|
+
- `execution/inprocess_strategy.py`: Same-process execution
|
|
252
|
+
- `execution/subprocess_strategy.py`: Isolated process execution
|
|
253
|
+
- `execution/wrappers/`: Enhanced executors (caching, retries, etc.)
|
|
254
|
+
|
|
255
|
+
4. **Plugins**: Extensible plugin system
|
|
256
|
+
- `plugins/discovery.py`: Plugin discovery mechanism
|
|
257
|
+
- `plugins/parsers/`: Parser plugins for different formats
|
|
258
|
+
|
|
259
|
+
5. **Utils**: Shared utilities
|
|
260
|
+
- `utils/logging.py`: Structured logging system
|
|
261
|
+
- `utils/validation.py`: Argument and result validation
|
|
262
|
+
|
|
263
|
+
6. **Core**: Central components
|
|
264
|
+
- `core/processor.py`: Main processor for handling tool calls
|
|
265
|
+
- `core/exceptions.py`: Exception hierarchy
|
|
266
|
+
|
|
267
|
+
## Examples
|
|
268
|
+
|
|
269
|
+
The repository includes several example scripts:
|
|
270
|
+
|
|
271
|
+
- `examples/tool_registry_example.py`: Demonstrates tool registration and usage
|
|
272
|
+
- `examples/plugin_example.py`: Shows how to create and use custom plugins
|
|
273
|
+
- `examples/tool_calling_example_usage.py`: Basic example demonstrating tool execution
|
|
274
|
+
|
|
275
|
+
Run examples with:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Registry example
|
|
279
|
+
uv run examples/tool_registry_example.py
|
|
280
|
+
|
|
281
|
+
# Plugin example
|
|
282
|
+
uv run examples/plugin_example.py
|
|
283
|
+
|
|
284
|
+
# Tool execution example
|
|
285
|
+
uv run examples/tool_calling_example_usage.py
|
|
286
|
+
|
|
287
|
+
# Enable debug logging
|
|
288
|
+
LOGLEVEL=DEBUG uv run examples/tool_calling_example_usage.py
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
chuk_tool_processor/__init__.py,sha256=a4pDi8hta4hjhijLGcv3vlWL8iu3F9EynkmB3si7-hg,33
|
|
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=wRVFLHMWikanFb8Zo8Hdp1XDnBmxzVYaNdWYnCyKI44,10164
|
|
5
|
+
chuk_tool_processor/execution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
chuk_tool_processor/execution/tool_executor.py,sha256=e1EHE-744uJuB1XeZZF_6VT25Yg1RCd8XI3v8uOrOSo,1794
|
|
7
|
+
chuk_tool_processor/execution/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
chuk_tool_processor/execution/strategies/inprocess_strategy.py,sha256=i0wsauDOij0w5VP2chmSx5EOPXsuPcDLM7bQ8-CYLIM,7305
|
|
9
|
+
chuk_tool_processor/execution/strategies/subprocess_strategy.py,sha256=Ev3brLfKF6ylH0Ck20ahML9_miFq9vu33DeER2ntf2k,3792
|
|
10
|
+
chuk_tool_processor/execution/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
chuk_tool_processor/execution/wrappers/caching.py,sha256=dA2OULPQ9xCZj-r3ev5LtsCDFDPgoz8tr70YCX5A4Wg,7714
|
|
12
|
+
chuk_tool_processor/execution/wrappers/rate_limiting.py,sha256=pFqD1vLzOtJzsWzpEI7J786gOAbdFY0gVeiO7ElBXbA,4991
|
|
13
|
+
chuk_tool_processor/execution/wrappers/retry.py,sha256=tRIuT5iNAYUY3r9y3shouWCxJZB5VONkBC9qPBaaVdc,6386
|
|
14
|
+
chuk_tool_processor/models/__init__.py,sha256=TC__rdVa0lQsmJHM_hbLDPRgToa_pQT_UxRcPZk6iVw,40
|
|
15
|
+
chuk_tool_processor/models/execution_strategy.py,sha256=s4yGAlVn_tqzpaqQPTTociOWhu6fxQWsd9BxoMhb4yU,511
|
|
16
|
+
chuk_tool_processor/models/tool_call.py,sha256=RZOnx2YczkJN6ym2PLiI4CRzP2qU_5hpMtHxMcFOxY4,298
|
|
17
|
+
chuk_tool_processor/models/tool_result.py,sha256=fqHuRC8bLek1PAwyhLOoKjRCLhpSm-mhDgLpsItjZ60,1532
|
|
18
|
+
chuk_tool_processor/plugins/__init__.py,sha256=QO_ipvlsWG-rbaqGzj6-YtD7zi7Lx26hw-Cqha4MuWc,48
|
|
19
|
+
chuk_tool_processor/plugins/discovery.py,sha256=K0sncdDmswH2tS_k-siJYLfEHzwMlU4iQVPX5kb6SZU,6370
|
|
20
|
+
chuk_tool_processor/plugins/parsers/__init__.py,sha256=QO_ipvlsWG-rbaqGzj6-YtD7zi7Lx26hw-Cqha4MuWc,48
|
|
21
|
+
chuk_tool_processor/plugins/parsers/function_call_tool.py,sha256=h7hbw25j-H961Pe7VVM0tSoPyP0IaprETmtDKSB2Teg,3945
|
|
22
|
+
chuk_tool_processor/plugins/parsers/json_tool.py,sha256=20maA7jyEe6NFY7Efg_HqKhBkIQ5JhuAIKNfvjytEds,573
|
|
23
|
+
chuk_tool_processor/plugins/parsers/xml_tool.py,sha256=QhywgQFEfticAf6LOfMTgzHN37lgZBqLFGXzNqGK5v8,1255
|
|
24
|
+
chuk_tool_processor/registry/__init__.py,sha256=mLV6J2e7dcPva7S2gE6X3G1OElTXO0iTMzDC6-jL1SI,647
|
|
25
|
+
chuk_tool_processor/registry/decorators.py,sha256=WecmzWK2RliMO0xmWEifj7xBqACoGfm2rz1hxcgtkrI,1346
|
|
26
|
+
chuk_tool_processor/registry/interface.py,sha256=40KFbMKzjnwf6iki9aeWBx5c3Dq3Tadr78y-Ko-IYsM,2299
|
|
27
|
+
chuk_tool_processor/registry/metadata.py,sha256=zoSv8QnncqMtvEo7nj_pGKKQohw6maBVDiInXBoNaxY,1744
|
|
28
|
+
chuk_tool_processor/registry/provider.py,sha256=lsolfDqKelvxEkZR_qbHPe9iDZFHobnk5sm_LvSTdTU,1318
|
|
29
|
+
chuk_tool_processor/registry/providers/__init__.py,sha256=_0dg4YhyfAV0TXuR_i4ewXPU8fY7odFd1RJWCmHIXmk,1326
|
|
30
|
+
chuk_tool_processor/registry/providers/memory.py,sha256=Re5B0PPRETJOUVz6_gwMEJDBmYQulTtqkfnZacgxC8s,5552
|
|
31
|
+
chuk_tool_processor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
chuk_tool_processor/utils/logging.py,sha256=cr3N3EMr7EqLj6SW-N-i4LJTegodUDtl3BxGvZbc26Q,7846
|
|
33
|
+
chuk_tool_processor/utils/validation.py,sha256=kincqcVrYl2XUU3BHwqPAcQa6L-Cx0Oees4L8qwOK54,5994
|
|
34
|
+
chuk_tool_processor-0.1.0.dist-info/METADATA,sha256=SRLHsrpXRZeFHvWYu3XWtWOgKaoXG6l1g9VhjSBVskM,9221
|
|
35
|
+
chuk_tool_processor-0.1.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
36
|
+
chuk_tool_processor-0.1.0.dist-info/top_level.txt,sha256=7lTsnuRx4cOW4U2sNJWNxl4ZTt_J1ndkjTbj3pHPY5M,20
|
|
37
|
+
chuk_tool_processor-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
chuk_tool_processor
|