rakam-systems-agent 0.1.1rc7__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.
@@ -0,0 +1,431 @@
1
+ """
2
+ Example tools demonstrating both direct and MCP invocation patterns.
3
+ These tools can be used for testing and as templates for custom tools.
4
+ """
5
+ from __future__ import annotations
6
+ import asyncio
7
+ from datetime import datetime
8
+ from typing import Dict, List, Any, Optional
9
+ from rakam_systems_core.ai_core.interfaces.tool import ToolComponent
10
+
11
+
12
+ # === Simple Direct Tools ===
13
+
14
+ async def get_current_weather(location: str, units: str = "celsius") -> Dict[str, Any]:
15
+ """
16
+ Get the current weather for a location (mock implementation).
17
+
18
+ Args:
19
+ location: City name or location
20
+ units: Temperature units (celsius or fahrenheit)
21
+
22
+ Returns:
23
+ Dictionary with weather information
24
+ """
25
+ await asyncio.sleep(0.5) # Simulate API call
26
+ return {
27
+ "location": location,
28
+ "temperature": 22 if units == "celsius" else 72,
29
+ "units": units,
30
+ "condition": "sunny",
31
+ "humidity": 45,
32
+ "timestamp": datetime.now().isoformat(),
33
+ }
34
+
35
+
36
+ async def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
37
+ """
38
+ Calculate distance between two geographic coordinates (mock implementation).
39
+
40
+ Args:
41
+ lat1: Latitude of first point
42
+ lon1: Longitude of first point
43
+ lat2: Latitude of second point
44
+ lon2: Longitude of second point
45
+
46
+ Returns:
47
+ Distance in kilometers
48
+ """
49
+ await asyncio.sleep(0.3)
50
+ # Simplified calculation (not accurate, just for demo)
51
+ import math
52
+ dlat = lat2 - lat1
53
+ dlon = lon2 - lon1
54
+ distance = math.sqrt(dlat**2 + dlon**2) * 111 # Rough km conversion
55
+ return round(distance, 2)
56
+
57
+
58
+ def format_currency(amount: float, currency: str = "USD") -> str:
59
+ """
60
+ Format a number as currency.
61
+
62
+ Args:
63
+ amount: Amount to format
64
+ currency: Currency code (USD, EUR, GBP, etc.)
65
+
66
+ Returns:
67
+ Formatted currency string
68
+ """
69
+ symbols = {
70
+ "USD": "$",
71
+ "EUR": "€",
72
+ "GBP": "£",
73
+ "JPY": "¥",
74
+ }
75
+ symbol = symbols.get(currency, currency + " ")
76
+ return f"{symbol}{amount:,.2f}"
77
+
78
+
79
+ async def translate_text(text: str, target_language: str = "en") -> Dict[str, str]:
80
+ """
81
+ Translate text to target language (mock implementation).
82
+
83
+ Args:
84
+ text: Text to translate
85
+ target_language: Target language code (en, es, fr, de, etc.)
86
+
87
+ Returns:
88
+ Dictionary with original and translated text
89
+ """
90
+ await asyncio.sleep(0.7)
91
+ # Mock translation - just returns the same text with a note
92
+ translations = {
93
+ "en": text,
94
+ "es": f"[ES] {text}",
95
+ "fr": f"[FR] {text}",
96
+ "de": f"[DE] {text}",
97
+ }
98
+ return {
99
+ "original": text,
100
+ "translated": translations.get(target_language, f"[{target_language}] {text}"),
101
+ "target_language": target_language,
102
+ }
103
+
104
+
105
+ def analyze_sentiment(text: str) -> Dict[str, Any]:
106
+ """
107
+ Analyze sentiment of text (mock implementation).
108
+
109
+ Args:
110
+ text: Text to analyze
111
+
112
+ Returns:
113
+ Dictionary with sentiment analysis results
114
+ """
115
+ # Very simple mock sentiment analysis
116
+ positive_words = ["good", "great", "excellent",
117
+ "amazing", "wonderful", "happy"]
118
+ negative_words = ["bad", "terrible", "awful", "horrible", "sad", "angry"]
119
+
120
+ text_lower = text.lower()
121
+ positive_count = sum(1 for word in positive_words if word in text_lower)
122
+ negative_count = sum(1 for word in negative_words if word in text_lower)
123
+
124
+ if positive_count > negative_count:
125
+ sentiment = "positive"
126
+ score = 0.7
127
+ elif negative_count > positive_count:
128
+ sentiment = "negative"
129
+ score = 0.3
130
+ else:
131
+ sentiment = "neutral"
132
+ score = 0.5
133
+
134
+ return {
135
+ "text": text,
136
+ "sentiment": sentiment,
137
+ "score": score,
138
+ "positive_indicators": positive_count,
139
+ "negative_indicators": negative_count,
140
+ }
141
+
142
+
143
+ # === Tool Components ===
144
+
145
+ class WebSearchTool(ToolComponent):
146
+ """
147
+ Web search tool component (mock implementation).
148
+ Can be used directly or exposed via MCP.
149
+ """
150
+
151
+ def __init__(self, name: str = "web_search", config: Optional[Dict] = None):
152
+ super().__init__(
153
+ name=name,
154
+ config=config,
155
+ description="Search the web for information",
156
+ json_schema={
157
+ "type": "object",
158
+ "properties": {
159
+ "query": {
160
+ "type": "string",
161
+ "description": "Search query"
162
+ }
163
+ },
164
+ "required": ["query"],
165
+ "additionalProperties": False,
166
+ }
167
+ )
168
+
169
+ def run(self, query: str) -> Dict[str, Any]:
170
+ """
171
+ Perform a web search (mock implementation).
172
+
173
+ Args:
174
+ query: Search query
175
+
176
+ Returns:
177
+ Dictionary with search results
178
+ """
179
+ # Mock search results
180
+ return {
181
+ "query": query,
182
+ "results": [
183
+ {
184
+ "title": f"Result 1 for '{query}'",
185
+ "url": "https://example.com/1",
186
+ "snippet": f"This is a mock result for the query: {query}",
187
+ },
188
+ {
189
+ "title": f"Result 2 for '{query}'",
190
+ "url": "https://example.com/2",
191
+ "snippet": f"Another mock result about {query}",
192
+ },
193
+ ],
194
+ "total_results": 2,
195
+ }
196
+
197
+ async def arun(self, query: str) -> Dict[str, Any]:
198
+ """Async version of run."""
199
+ await asyncio.sleep(0.8) # Simulate network delay
200
+ return self.run(query)
201
+
202
+
203
+ class DatabaseQueryTool(ToolComponent):
204
+ """
205
+ Database query tool component (mock implementation).
206
+ Demonstrates a tool that could be exposed via MCP for security.
207
+ """
208
+
209
+ def __init__(self, name: str = "database_query", config: Optional[Dict] = None):
210
+ super().__init__(
211
+ name=name,
212
+ config=config,
213
+ description="Query the database",
214
+ json_schema={
215
+ "type": "object",
216
+ "properties": {
217
+ "query": {
218
+ "type": "string",
219
+ "description": "Database query string"
220
+ }
221
+ },
222
+ "required": ["query"],
223
+ "additionalProperties": False,
224
+ }
225
+ )
226
+ self._mock_db = {
227
+ "users": [
228
+ {"id": 1, "name": "Alice", "email": "alice@example.com"},
229
+ {"id": 2, "name": "Bob", "email": "bob@example.com"},
230
+ ],
231
+ "products": [
232
+ {"id": 1, "name": "Widget", "price": 19.99},
233
+ {"id": 2, "name": "Gadget", "price": 29.99},
234
+ ],
235
+ }
236
+
237
+ def run(self, query: str) -> Dict[str, Any]:
238
+ """
239
+ Execute a database query (mock implementation).
240
+
241
+ Args:
242
+ query: Query string (simplified, e.g., "SELECT * FROM users")
243
+
244
+ Returns:
245
+ Dictionary with query results
246
+ """
247
+ # Very simple mock query parser
248
+ query_lower = query.lower()
249
+
250
+ if "users" in query_lower:
251
+ table = "users"
252
+ results = self._mock_db["users"]
253
+ elif "products" in query_lower:
254
+ table = "products"
255
+ results = self._mock_db["products"]
256
+ else:
257
+ table = "unknown"
258
+ results = []
259
+
260
+ return {
261
+ "query": query,
262
+ "table": table,
263
+ "results": results,
264
+ "count": len(results),
265
+ }
266
+
267
+ async def arun(self, query: str) -> Dict[str, Any]:
268
+ """Async version of run."""
269
+ await asyncio.sleep(0.4) # Simulate database query time
270
+ return self.run(query)
271
+
272
+
273
+ class FileProcessorTool(ToolComponent):
274
+ """
275
+ File processor tool component (mock implementation).
276
+ Demonstrates a tool that processes files.
277
+ """
278
+
279
+ def __init__(self, name: str = "file_processor", config: Optional[Dict] = None):
280
+ super().__init__(
281
+ name=name,
282
+ config=config,
283
+ description="Process and analyze files",
284
+ json_schema={
285
+ "type": "object",
286
+ "properties": {
287
+ "query": {
288
+ "type": "string",
289
+ "description": "File path or processing command"
290
+ }
291
+ },
292
+ "required": ["query"],
293
+ "additionalProperties": False,
294
+ }
295
+ )
296
+
297
+ def run(self, query: str) -> Dict[str, Any]:
298
+ """
299
+ Process a file (mock implementation).
300
+
301
+ Args:
302
+ query: File path or processing command
303
+
304
+ Returns:
305
+ Dictionary with processing results
306
+ """
307
+ return {
308
+ "file": query,
309
+ "status": "processed",
310
+ "lines": 42,
311
+ "words": 256,
312
+ "characters": 1543,
313
+ "type": "text/plain",
314
+ }
315
+
316
+ async def arun(self, query: str) -> Dict[str, Any]:
317
+ """Async version of run."""
318
+ await asyncio.sleep(0.6) # Simulate file processing
319
+ return self.run(query)
320
+
321
+
322
+ # === Helper Functions for Tool Registration ===
323
+
324
+ def get_all_example_tools() -> List[Dict[str, Any]]:
325
+ """
326
+ Get configuration for all example tools.
327
+
328
+ Returns:
329
+ List of tool configuration dictionaries
330
+ """
331
+ return [
332
+ {
333
+ "name": "get_current_weather",
334
+ "function": get_current_weather,
335
+ "description": "Get the current weather for a location",
336
+ "json_schema": {
337
+ "type": "object",
338
+ "properties": {
339
+ "location": {
340
+ "type": "string",
341
+ "description": "City name or location"
342
+ },
343
+ "units": {
344
+ "type": "string",
345
+ "description": "Temperature units (celsius or fahrenheit)",
346
+ "enum": ["celsius", "fahrenheit"],
347
+ "default": "celsius"
348
+ }
349
+ },
350
+ "required": ["location"],
351
+ "additionalProperties": False,
352
+ },
353
+ "category": "utility",
354
+ "tags": ["weather", "external"],
355
+ },
356
+ {
357
+ "name": "calculate_distance",
358
+ "function": calculate_distance,
359
+ "description": "Calculate distance between two geographic coordinates",
360
+ "json_schema": {
361
+ "type": "object",
362
+ "properties": {
363
+ "lat1": {"type": "number", "description": "Latitude of first point"},
364
+ "lon1": {"type": "number", "description": "Longitude of first point"},
365
+ "lat2": {"type": "number", "description": "Latitude of second point"},
366
+ "lon2": {"type": "number", "description": "Longitude of second point"},
367
+ },
368
+ "required": ["lat1", "lon1", "lat2", "lon2"],
369
+ "additionalProperties": False,
370
+ },
371
+ "category": "math",
372
+ "tags": ["geography", "calculation"],
373
+ },
374
+ {
375
+ "name": "format_currency",
376
+ "function": format_currency,
377
+ "description": "Format a number as currency",
378
+ "json_schema": {
379
+ "type": "object",
380
+ "properties": {
381
+ "amount": {"type": "number", "description": "Amount to format"},
382
+ "currency": {
383
+ "type": "string",
384
+ "description": "Currency code",
385
+ "enum": ["USD", "EUR", "GBP", "JPY"],
386
+ "default": "USD"
387
+ },
388
+ },
389
+ "required": ["amount"],
390
+ "additionalProperties": False,
391
+ },
392
+ "category": "utility",
393
+ "tags": ["formatting", "currency"],
394
+ },
395
+ {
396
+ "name": "translate_text",
397
+ "function": translate_text,
398
+ "description": "Translate text to target language",
399
+ "json_schema": {
400
+ "type": "object",
401
+ "properties": {
402
+ "text": {"type": "string", "description": "Text to translate"},
403
+ "target_language": {
404
+ "type": "string",
405
+ "description": "Target language code",
406
+ "enum": ["en", "es", "fr", "de"],
407
+ "default": "en"
408
+ },
409
+ },
410
+ "required": ["text"],
411
+ "additionalProperties": False,
412
+ },
413
+ "category": "nlp",
414
+ "tags": ["translation", "language"],
415
+ },
416
+ {
417
+ "name": "analyze_sentiment",
418
+ "function": analyze_sentiment,
419
+ "description": "Analyze sentiment of text",
420
+ "json_schema": {
421
+ "type": "object",
422
+ "properties": {
423
+ "text": {"type": "string", "description": "Text to analyze"},
424
+ },
425
+ "required": ["text"],
426
+ "additionalProperties": False,
427
+ },
428
+ "category": "nlp",
429
+ "tags": ["sentiment", "analysis"],
430
+ },
431
+ ]