kader 0.1.5__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.
kader/tools/README.md ADDED
@@ -0,0 +1,483 @@
1
+ # Kader Tools Documentation
2
+
3
+ Kader Tools provides a versatile, provider-agnostic framework for creating and managing agentic tools that can be used with any LLM provider (OpenAI, Google, Anthropic, Mistral, and others).
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Available Tools](#available-tools)
8
+ 2. [Using Tools](#using-tools)
9
+ 3. [Creating Custom Tools](#creating-custom-tools)
10
+ 4. [Tool Registry](#tool-registry)
11
+ 5. [Provider Compatibility](#provider-compatibility)
12
+
13
+ ## Available Tools
14
+
15
+ ### File System Tools
16
+
17
+ - **ReadFileTool**: Read the contents of a file with optional line range selection
18
+ - **ReadDirectoryTool**: List directory contents with recursive option
19
+ - **WriteFileTool**: Write content to a file, with optional directory creation
20
+ - **ReplaceLinesTool**: Replace or insert lines in a file
21
+ - **SearchInDirectoryTool**: Search for files in a directory by name or content
22
+
23
+ ### Web Tools
24
+
25
+ - **WebSearchTool**: Search the web for information with configurable result limit
26
+ - **WebFetchTool**: Fetch and extract text content from a web page
27
+
28
+ ### Command Execution Tool
29
+
30
+ - **CommandExecutorTool**: Execute command line operations with OS-appropriate validation
31
+
32
+ ### RAG (Retrieval Augmented Generation) Tools
33
+
34
+ - **RAGSearchTool**: Search through local files using semantic embeddings
35
+ - **RAGIndex**: Build and manage semantic indexes of your local files
36
+
37
+ ## Using Tools
38
+
39
+ Here's how to use the available tools in your applications:
40
+
41
+ ### Basic Tool Usage
42
+
43
+ ```python
44
+ from kader.tools import ReadFileTool
45
+
46
+ # Create a tool instance
47
+ read_tool = ReadFileTool()
48
+
49
+ # Execute the tool
50
+ content = read_tool.execute(path="README.md")
51
+ print(content)
52
+ ```
53
+
54
+ ### Using with Tool Registry
55
+
56
+ ```python
57
+ from kader.tools import ToolRegistry, ReadFileTool, WriteFileTool
58
+
59
+ # Create a registry and register tools
60
+ registry = ToolRegistry()
61
+ registry.register(ReadFileTool())
62
+ registry.register(WriteFileTool())
63
+
64
+ # Get tools
65
+ available_tools = registry.tools
66
+ for tool in available_tools:
67
+ print(f"Available tool: {tool.name}")
68
+
69
+ # Get a specific tool by name
70
+ read_tool = registry.get("read_file")
71
+ if read_tool:
72
+ result = read_tool.execute(path="README.md")
73
+ print(result)
74
+ ```
75
+
76
+ ### Asynchronous Execution
77
+
78
+ All tools support both synchronous and asynchronous execution:
79
+
80
+ ```python
81
+ import asyncio
82
+ from kader.tools import ReadFileTool
83
+
84
+ async def async_example():
85
+ tool = ReadFileTool()
86
+
87
+ # Synchronous execution
88
+ sync_result = tool.execute(path="README.md")
89
+
90
+ # Asynchronous execution
91
+ async_result = await tool.aexecute(path="README.md")
92
+
93
+ return sync_result, async_result
94
+
95
+ # Run the async function
96
+ sync_result, async_result = asyncio.run(async_example())
97
+ ```
98
+
99
+ ## Creating Custom Tools
100
+
101
+ Creating custom tools is straightforward with the `BaseTool` class:
102
+
103
+ ### Basic Custom Tool
104
+
105
+ ```python
106
+ from kader.tools.base import BaseTool, ParameterSchema, ToolCategory
107
+
108
+ class GreetingTool(BaseTool[str]):
109
+ """
110
+ A simple tool that generates a personalized greeting.
111
+ """
112
+
113
+ def __init__(self):
114
+ super().__init__(
115
+ name="greeting_tool",
116
+ description="Generate a personalized greeting message",
117
+ parameters=[
118
+ ParameterSchema(
119
+ name="name",
120
+ type="string",
121
+ description="The name to greet",
122
+ ),
123
+ ParameterSchema(
124
+ name="greeting_type",
125
+ type="string",
126
+ description="Type of greeting (formal, casual, friendly)",
127
+ required=False,
128
+ default="casual",
129
+ enum=["formal", "casual", "friendly"]
130
+ ),
131
+ ],
132
+ category=ToolCategory.UTILITY,
133
+ )
134
+
135
+ def execute(self, name: str, greeting_type: str = "casual") -> str:
136
+ """
137
+ Execute the greeting tool.
138
+ """
139
+ greetings = {
140
+ "formal": f"Good day, {name}!",
141
+ "casual": f"Hello, {name}!",
142
+ "friendly": f"Hey there, {name}! How's it going?"
143
+ }
144
+
145
+ return greetings.get(greeting_type, greetings["casual"])
146
+
147
+ async def aexecute(self, name: str, greeting_type: str = "casual") -> str:
148
+ """
149
+ Asynchronous execution of the tool.
150
+ """
151
+ import asyncio
152
+ # Simulate async operation if needed
153
+ await asyncio.sleep(0.01) # Placeholder for actual async work
154
+ return self.execute(name, greeting_type)
155
+
156
+ # Using the custom tool
157
+ tool = GreetingTool()
158
+ print(tool.execute(name="Alice", greeting_type="friendly"))
159
+ # Output: Hey there, Alice! How's it going?
160
+ ```
161
+
162
+ ### Tool with Complex Return Types
163
+
164
+ ```python
165
+ from typing import Dict, Any
166
+ from kader.tools.base import BaseTool, ParameterSchema, ToolCategory
167
+
168
+ class MathCalculatorTool(BaseTool[Dict[str, Any]]):
169
+ """
170
+ A tool that performs basic mathematical operations.
171
+ """
172
+
173
+ def __init__(self):
174
+ super().__init__(
175
+ name="math_calculator",
176
+ description="Perform basic mathematical operations",
177
+ parameters=[
178
+ ParameterSchema(
179
+ name="operation",
180
+ type="string",
181
+ description="The operation to perform (add, subtract, multiply, divide)",
182
+ enum=["add", "subtract", "multiply", "divide"]
183
+ ),
184
+ ParameterSchema(
185
+ name="a",
186
+ type="number",
187
+ description="First operand"
188
+ ),
189
+ ParameterSchema(
190
+ name="b",
191
+ type="number",
192
+ description="Second operand"
193
+ )
194
+ ],
195
+ category=ToolCategory.UTILITY,
196
+ )
197
+
198
+ def execute(self, operation: str, a: float, b: float) -> Dict[str, Any]:
199
+ """
200
+ Execute the mathematical operation.
201
+ """
202
+ operations = {
203
+ "add": lambda x, y: x + y,
204
+ "subtract": lambda x, y: x - y,
205
+ "multiply": lambda x, y: x * y,
206
+ "divide": lambda x, y: x / y if y != 0 else float('inf')
207
+ }
208
+
209
+ if operation not in operations:
210
+ return {
211
+ "error": f"Invalid operation '{operation}'. Supported operations: {list(operations.keys())}",
212
+ "result": None
213
+ }
214
+
215
+ try:
216
+ result = operations[operation](a, b)
217
+ return {
218
+ "operation": f"{a} {operation} {b}",
219
+ "result": result,
220
+ "success": True
221
+ }
222
+ except Exception as e:
223
+ return {
224
+ "error": f"Error during calculation: {str(e)}",
225
+ "result": None,
226
+ "success": False
227
+ }
228
+
229
+ async def aexecute(self, operation: str, a: float, b: float) -> Dict[str, Any]:
230
+ """
231
+ Asynchronous execution of the calculator.
232
+ """
233
+ import asyncio
234
+ await asyncio.sleep(0.01) # Simulate async operation
235
+ return self.execute(operation, a, b)
236
+ ```
237
+
238
+ ### Command Execution Tool Example
239
+
240
+ The CommandExecutorTool included in this package demonstrates advanced features:
241
+
242
+ ```python
243
+ from kader.tools.exec_commands import CommandExecutorTool
244
+
245
+ # Create the command executor tool
246
+ cmd_tool = CommandExecutorTool()
247
+
248
+ # Execute a command (with OS validation)
249
+ result = cmd_tool.execute(command="echo 'Hello, World!'", timeout=10)
250
+ print(result)
251
+
252
+ # On Windows, this would warn about Unix-specific commands:
253
+ result = cmd_tool.execute(command="ls -la") # Shows validation error
254
+ print(result)
255
+ ```
256
+
257
+ ## Tool Registry
258
+
259
+ The `ToolRegistry` provides a centralized way to manage multiple tools and execute them by name:
260
+
261
+ ### Basic Registry Usage
262
+
263
+ ```python
264
+ from kader.tools import ToolRegistry, ReadFileTool, WriteFileTool, CommandExecutorTool
265
+
266
+ # Create a registry
267
+ registry = ToolRegistry()
268
+
269
+ # Register individual tools
270
+ registry.register(ReadFileTool())
271
+ registry.register(WriteFileTool())
272
+ registry.register(CommandExecutorTool())
273
+
274
+ # Or register multiple tools at once
275
+ from kader.tools.filesys import get_filesystem_tools
276
+ filesystem_tools = get_filesystem_tools()
277
+ for tool in filesystem_tools:
278
+ registry.register(tool)
279
+
280
+ # Get tools by name
281
+ read_tool = registry.get("read_file")
282
+ if read_tool:
283
+ result = read_tool.execute(path="README.md")
284
+ print(result)
285
+
286
+ # Get all registered tool names
287
+ tool_names = registry.names
288
+ print("Registered tools:", tool_names)
289
+
290
+ # Get all tools
291
+ all_tools = registry.tools
292
+ print(f"Total tools: {len(all_tools)}")
293
+
294
+ # Get tool schemas for LLM provider integration
295
+ schemas = registry.to_provider_format(provider="openai")
296
+ ```
297
+
298
+ ### Registry with Provider Compatibility
299
+
300
+ ```python
301
+ from kader.tools import ToolRegistry
302
+ from kader.tools.filesys import ReadFileTool
303
+ from kader.tools.web import WebSearchTool
304
+
305
+ # Create registry and register tools
306
+ registry = ToolRegistry()
307
+ registry.register(ReadFileTool())
308
+ registry.register(WebSearchTool())
309
+
310
+ # Get schemas formatted for different providers
311
+ openai_schemas = registry.to_provider_format("openai")
312
+ anthropic_schemas = registry.to_provider_format("anthropic")
313
+ google_schemas = registry.to_provider_format("google")
314
+ mistral_schemas = registry.to_provider_format("mistral")
315
+ ollama_schemas = registry.to_provider_format("ollama")
316
+
317
+ # Use with your LLM provider
318
+ # Example with OpenAI:
319
+ # openai_client.chat.completions.create(
320
+ # model="gpt-4",
321
+ # messages=[...],
322
+ # tools=openai_schemas,
323
+ # tool_choice="auto",
324
+ # )
325
+ ```
326
+
327
+ ### Working with Tool Results
328
+
329
+ ```python
330
+ from kader.tools import ToolRegistry, ReadFileTool, ToolCall
331
+ from kader.tools.base import ToolResult
332
+
333
+ registry = ToolRegistry()
334
+ registry.register(ReadFileTool())
335
+
336
+ # Create a tool call (this would typically come from an LLM response)
337
+ tool_call = ToolCall(
338
+ id="call_123",
339
+ name="read_file",
340
+ arguments={"path": "README.md"},
341
+ raw_arguments='{"path": "README.md"}'
342
+ )
343
+
344
+ # Execute the tool call through the registry
345
+ result = registry.run(tool_call)
346
+
347
+ # ToolResult has status, content, and optional data
348
+ print(f"Status: {result.status}")
349
+ print(f"Content: {result.content}")
350
+
351
+ # Convert to provider-specific format
352
+ openai_format = result.to_provider_format("openai")
353
+ anthropic_format = result.to_provider_format("anthropic")
354
+
355
+ # Working with the CommandExecutorTool specifically
356
+ cmd_tool_call = ToolCall(
357
+ id="cmd_call_456",
358
+ name="execute_command",
359
+ arguments={"command": "echo Hello from command executor"},
360
+ raw_arguments='{"command": "echo Hello from command executor"}'
361
+ )
362
+
363
+ cmd_result = registry.run(cmd_tool_call)
364
+ print(f"Command execution result: {cmd_result.content}")
365
+ ```
366
+
367
+ ## Provider Compatibility
368
+
369
+ Kader Tools are designed to work with multiple LLM providers seamlessly:
370
+
371
+ ### OpenAI Integration
372
+
373
+ ```python
374
+ from kader.tools import ToolRegistry
375
+ from kader.tools.filesys import ReadFileTool
376
+
377
+ registry = ToolRegistry()
378
+ registry.add_tool(ReadFileTool())
379
+
380
+ # Get tools in OpenAI format
381
+ openai_tools = registry.get_tool_schemas(provider="openai")
382
+
383
+ # Use with OpenAI
384
+ import openai
385
+ response = openai.ChatCompletion.create(
386
+ model="gpt-4",
387
+ messages=[
388
+ {"role": "user", "content": "Read the README.md file"}
389
+ ],
390
+ tools=openai_tools,
391
+ tool_choice="auto"
392
+ )
393
+
394
+ # Process tool calls from response
395
+ for choice in response.choices:
396
+ if choice.message.tool_calls:
397
+ for tool_call in choice.message.tool_calls:
398
+ result = registry.execute_tool_from_call(tool_call, "openai")
399
+ print(result.content)
400
+ ```
401
+
402
+ ### Anthropic Integration
403
+
404
+ ```python
405
+ from kader.tools import ToolRegistry
406
+ from kader.tools.filesys import ReadFileTool
407
+
408
+ registry = ToolRegistry()
409
+ registry.add_tool(ReadFileTool())
410
+
411
+ # Get tools in Anthropic format
412
+ anthropic_tools = registry.get_tool_schemas(provider="anthropic")
413
+
414
+ # Use with Anthropic
415
+ import anthropic
416
+ client = anthropic.Anthropic()
417
+ response = client.messages.create(
418
+ model="claude-3-opus-20240229",
419
+ max_tokens=1000,
420
+ messages=[
421
+ {"role": "user", "content": "Read the configuration file"}
422
+ ],
423
+ tools=anthropic_tools
424
+ )
425
+
426
+ # Process tool use blocks from response
427
+ for content_block in response.content:
428
+ if content_block.type == "tool_use":
429
+ result = registry.execute_tool_from_call(content_block, "anthropic")
430
+ print(result.content)
431
+ ```
432
+
433
+ ### Google (Gemini) Integration
434
+
435
+ ```python
436
+ from kader.tools import ToolRegistry
437
+ from kader.tools.filesys import ReadFileTool
438
+
439
+ registry = ToolRegistry()
440
+ registry.add_tool(ReadFileTool())
441
+
442
+ # Get tools in Google format
443
+ google_tools = registry.get_tool_schemas(provider="google")
444
+
445
+ # Use with Google Gemini
446
+ import google.generativeai as genai
447
+ model = genai.GenerativeModel(model_name="gemini-pro", tools=google_tools)
448
+
449
+ response = model.generate_content("Read the project's README file")
450
+
451
+ # Process function calls from response
452
+ for part in response.parts:
453
+ if hasattr(part, 'function_call'):
454
+ result = registry.execute_tool_from_call(part.function_call, "google")
455
+ print(result.content)
456
+ ```
457
+
458
+ ## Best Practices
459
+
460
+ 1. **Always validate inputs** - Use the parameter schema validation provided by BaseTool
461
+ 2. **Handle errors gracefully** - Implement proper error handling in your tool's execute method
462
+ 3. **Follow the category system** - Use appropriate ToolCategory values for organization
463
+ 4. **Provide clear descriptions** - Write clear, concise descriptions for your tools and their parameters
464
+ 5. **Consider security** - For file system operations, always validate paths to prevent directory traversal
465
+ 6. **Support both sync and async** - Implement both `execute` and `aexecute` methods
466
+ 7. **Use structured return types** - When possible, return structured data that can be processed by LLMs
467
+
468
+ ## File System Security
469
+
470
+ All file system tools operate relative to the current working directory (CWD) for security. Paths are validated to ensure they don't escape the allowed directory:
471
+
472
+ ```python
473
+ from pathlib import Path
474
+ from kader.tools.filesys import ReadFileTool
475
+
476
+ # Tools default to CWD but you can specify a different base
477
+ custom_tool = ReadFileTool(base_path=Path("/safe/directory"))
478
+
479
+ # This will raise an error if path attempts to escape the base path:
480
+ # content = custom_tool.execute(path="../../../forbidden.txt") # ValueError!
481
+ ```
482
+
483
+ For more information on creating custom tools or using the registry, check out the examples directory or the source code documentation.
@@ -0,0 +1,130 @@
1
+ """
2
+ Kader Tools - Agentic tool definitions.
3
+
4
+ This module provides a provider-agnostic base class for defining tools
5
+ that can be used with any LLM provider.
6
+ """
7
+
8
+ from kader.tools.exec_commands import (
9
+ CommandExecutorTool,
10
+ )
11
+
12
+ from .base import (
13
+ # Core classes
14
+ BaseTool,
15
+ FunctionTool,
16
+ ParameterSchema,
17
+ # Type aliases
18
+ ParameterType,
19
+ ToolCall,
20
+ # Enums
21
+ ToolCategory,
22
+ ToolRegistry,
23
+ ToolResult,
24
+ ToolResultStatus,
25
+ # Schemas and data classes
26
+ ToolSchema,
27
+ # Decorator
28
+ tool,
29
+ )
30
+ from .filesys import (
31
+ EditFileTool,
32
+ GlobTool,
33
+ GrepTool,
34
+ ReadDirectoryTool,
35
+ ReadFileTool,
36
+ SearchInDirectoryTool,
37
+ WriteFileTool,
38
+ get_filesystem_tools,
39
+ )
40
+ from .filesystem import (
41
+ FilesystemBackend,
42
+ )
43
+ from .rag import (
44
+ DEFAULT_EMBEDDING_MODEL,
45
+ DocumentChunk,
46
+ RAGIndex,
47
+ RAGSearchTool,
48
+ SearchResult,
49
+ )
50
+ from .todo import TodoTool
51
+ from .web import (
52
+ WebFetchTool,
53
+ WebSearchTool,
54
+ )
55
+
56
+
57
+ def get_default_registry() -> ToolRegistry:
58
+ """
59
+ Get a registry populated with all standard tools.
60
+
61
+ Includes:
62
+ - Filesystem tools
63
+ - Command executor
64
+ - Web tools (search, fetch)
65
+ """
66
+ registry = ToolRegistry()
67
+
68
+ # 1. Filesystem Tools
69
+ for t in get_filesystem_tools():
70
+ registry.register(t)
71
+
72
+ # 2. Command Execution
73
+ # 2. Command Execution
74
+ registry.register(CommandExecutorTool())
75
+
76
+ # 3. Web Tools
77
+ # Note: These might fail if ollama is missing, so we wrap safely
78
+ try:
79
+ registry.register(WebSearchTool())
80
+ registry.register(WebFetchTool())
81
+ except ImportError:
82
+ pass
83
+
84
+ return registry
85
+
86
+
87
+ __all__ = [
88
+ # Core classes
89
+ "BaseTool",
90
+ "FunctionTool",
91
+ "ToolRegistry",
92
+ # Schemas and data classes
93
+ "ToolSchema",
94
+ "ParameterSchema",
95
+ "ToolCall",
96
+ "ToolResult",
97
+ # Enums
98
+ "ToolCategory",
99
+ # Decorator
100
+ "tool",
101
+ # Type aliases
102
+ "ParameterType",
103
+ "ToolResultStatus",
104
+ # RAG
105
+ "RAGIndex",
106
+ "RAGSearchTool",
107
+ "DocumentChunk",
108
+ "SearchResult",
109
+ "DEFAULT_EMBEDDING_MODEL",
110
+ # File System Tools
111
+ "ReadFileTool",
112
+ "ReadDirectoryTool",
113
+ "WriteFileTool",
114
+ "EditFileTool",
115
+ "GrepTool",
116
+ "GlobTool",
117
+ "SearchInDirectoryTool",
118
+ "get_filesystem_tools",
119
+ "FilesystemBackend",
120
+ # Web Tools
121
+ "WebSearchTool",
122
+ "WebFetchTool",
123
+ # Command Execution Tool
124
+ # Command Execution Tool
125
+ "CommandExecutorTool",
126
+ # Todo Tool
127
+ "TodoTool",
128
+ # Helpers
129
+ "get_default_registry",
130
+ ]