genxai-framework 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.
- cli/__init__.py +3 -0
- cli/commands/__init__.py +6 -0
- cli/commands/approval.py +85 -0
- cli/commands/audit.py +127 -0
- cli/commands/metrics.py +25 -0
- cli/commands/tool.py +389 -0
- cli/main.py +32 -0
- genxai/__init__.py +81 -0
- genxai/api/__init__.py +5 -0
- genxai/api/app.py +21 -0
- genxai/config/__init__.py +5 -0
- genxai/config/settings.py +37 -0
- genxai/connectors/__init__.py +19 -0
- genxai/connectors/base.py +122 -0
- genxai/connectors/kafka.py +92 -0
- genxai/connectors/postgres_cdc.py +95 -0
- genxai/connectors/registry.py +44 -0
- genxai/connectors/sqs.py +94 -0
- genxai/connectors/webhook.py +73 -0
- genxai/core/__init__.py +37 -0
- genxai/core/agent/__init__.py +32 -0
- genxai/core/agent/base.py +206 -0
- genxai/core/agent/config_io.py +59 -0
- genxai/core/agent/registry.py +98 -0
- genxai/core/agent/runtime.py +970 -0
- genxai/core/communication/__init__.py +6 -0
- genxai/core/communication/collaboration.py +44 -0
- genxai/core/communication/message_bus.py +192 -0
- genxai/core/communication/protocols.py +35 -0
- genxai/core/execution/__init__.py +22 -0
- genxai/core/execution/metadata.py +181 -0
- genxai/core/execution/queue.py +201 -0
- genxai/core/graph/__init__.py +30 -0
- genxai/core/graph/checkpoints.py +77 -0
- genxai/core/graph/edges.py +131 -0
- genxai/core/graph/engine.py +813 -0
- genxai/core/graph/executor.py +516 -0
- genxai/core/graph/nodes.py +161 -0
- genxai/core/graph/trigger_runner.py +40 -0
- genxai/core/memory/__init__.py +19 -0
- genxai/core/memory/base.py +72 -0
- genxai/core/memory/embedding.py +327 -0
- genxai/core/memory/episodic.py +448 -0
- genxai/core/memory/long_term.py +467 -0
- genxai/core/memory/manager.py +543 -0
- genxai/core/memory/persistence.py +297 -0
- genxai/core/memory/procedural.py +461 -0
- genxai/core/memory/semantic.py +526 -0
- genxai/core/memory/shared.py +62 -0
- genxai/core/memory/short_term.py +303 -0
- genxai/core/memory/vector_store.py +508 -0
- genxai/core/memory/working.py +211 -0
- genxai/core/state/__init__.py +6 -0
- genxai/core/state/manager.py +293 -0
- genxai/core/state/schema.py +115 -0
- genxai/llm/__init__.py +14 -0
- genxai/llm/base.py +150 -0
- genxai/llm/factory.py +329 -0
- genxai/llm/providers/__init__.py +1 -0
- genxai/llm/providers/anthropic.py +249 -0
- genxai/llm/providers/cohere.py +274 -0
- genxai/llm/providers/google.py +334 -0
- genxai/llm/providers/ollama.py +147 -0
- genxai/llm/providers/openai.py +257 -0
- genxai/llm/routing.py +83 -0
- genxai/observability/__init__.py +6 -0
- genxai/observability/logging.py +327 -0
- genxai/observability/metrics.py +494 -0
- genxai/observability/tracing.py +372 -0
- genxai/performance/__init__.py +39 -0
- genxai/performance/cache.py +256 -0
- genxai/performance/pooling.py +289 -0
- genxai/security/audit.py +304 -0
- genxai/security/auth.py +315 -0
- genxai/security/cost_control.py +528 -0
- genxai/security/default_policies.py +44 -0
- genxai/security/jwt.py +142 -0
- genxai/security/oauth.py +226 -0
- genxai/security/pii.py +366 -0
- genxai/security/policy_engine.py +82 -0
- genxai/security/rate_limit.py +341 -0
- genxai/security/rbac.py +247 -0
- genxai/security/validation.py +218 -0
- genxai/tools/__init__.py +21 -0
- genxai/tools/base.py +383 -0
- genxai/tools/builtin/__init__.py +131 -0
- genxai/tools/builtin/communication/__init__.py +15 -0
- genxai/tools/builtin/communication/email_sender.py +159 -0
- genxai/tools/builtin/communication/notification_manager.py +167 -0
- genxai/tools/builtin/communication/slack_notifier.py +118 -0
- genxai/tools/builtin/communication/sms_sender.py +118 -0
- genxai/tools/builtin/communication/webhook_caller.py +136 -0
- genxai/tools/builtin/computation/__init__.py +15 -0
- genxai/tools/builtin/computation/calculator.py +101 -0
- genxai/tools/builtin/computation/code_executor.py +183 -0
- genxai/tools/builtin/computation/data_validator.py +259 -0
- genxai/tools/builtin/computation/hash_generator.py +129 -0
- genxai/tools/builtin/computation/regex_matcher.py +201 -0
- genxai/tools/builtin/data/__init__.py +15 -0
- genxai/tools/builtin/data/csv_processor.py +213 -0
- genxai/tools/builtin/data/data_transformer.py +299 -0
- genxai/tools/builtin/data/json_processor.py +233 -0
- genxai/tools/builtin/data/text_analyzer.py +288 -0
- genxai/tools/builtin/data/xml_processor.py +175 -0
- genxai/tools/builtin/database/__init__.py +15 -0
- genxai/tools/builtin/database/database_inspector.py +157 -0
- genxai/tools/builtin/database/mongodb_query.py +196 -0
- genxai/tools/builtin/database/redis_cache.py +167 -0
- genxai/tools/builtin/database/sql_query.py +145 -0
- genxai/tools/builtin/database/vector_search.py +163 -0
- genxai/tools/builtin/file/__init__.py +17 -0
- genxai/tools/builtin/file/directory_scanner.py +214 -0
- genxai/tools/builtin/file/file_compressor.py +237 -0
- genxai/tools/builtin/file/file_reader.py +102 -0
- genxai/tools/builtin/file/file_writer.py +122 -0
- genxai/tools/builtin/file/image_processor.py +186 -0
- genxai/tools/builtin/file/pdf_parser.py +144 -0
- genxai/tools/builtin/test/__init__.py +15 -0
- genxai/tools/builtin/test/async_simulator.py +62 -0
- genxai/tools/builtin/test/data_transformer.py +99 -0
- genxai/tools/builtin/test/error_generator.py +82 -0
- genxai/tools/builtin/test/simple_math.py +94 -0
- genxai/tools/builtin/test/string_processor.py +72 -0
- genxai/tools/builtin/web/__init__.py +15 -0
- genxai/tools/builtin/web/api_caller.py +161 -0
- genxai/tools/builtin/web/html_parser.py +330 -0
- genxai/tools/builtin/web/http_client.py +187 -0
- genxai/tools/builtin/web/url_validator.py +162 -0
- genxai/tools/builtin/web/web_scraper.py +170 -0
- genxai/tools/custom/my_test_tool_2.py +9 -0
- genxai/tools/dynamic.py +105 -0
- genxai/tools/mcp_server.py +167 -0
- genxai/tools/persistence/__init__.py +6 -0
- genxai/tools/persistence/models.py +55 -0
- genxai/tools/persistence/service.py +322 -0
- genxai/tools/registry.py +227 -0
- genxai/tools/security/__init__.py +11 -0
- genxai/tools/security/limits.py +214 -0
- genxai/tools/security/policy.py +20 -0
- genxai/tools/security/sandbox.py +248 -0
- genxai/tools/templates.py +435 -0
- genxai/triggers/__init__.py +19 -0
- genxai/triggers/base.py +104 -0
- genxai/triggers/file_watcher.py +75 -0
- genxai/triggers/queue.py +68 -0
- genxai/triggers/registry.py +82 -0
- genxai/triggers/schedule.py +66 -0
- genxai/triggers/webhook.py +68 -0
- genxai/utils/__init__.py +1 -0
- genxai/utils/tokens.py +295 -0
- genxai_framework-0.1.0.dist-info/METADATA +495 -0
- genxai_framework-0.1.0.dist-info/RECORD +156 -0
- genxai_framework-0.1.0.dist-info/WHEEL +5 -0
- genxai_framework-0.1.0.dist-info/entry_points.txt +2 -0
- genxai_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
- genxai_framework-0.1.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""Data validator tool for validating data against schemas and rules."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from genxai.tools.base import Tool, ToolMetadata, ToolParameter, ToolCategory
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DataValidatorTool(Tool):
|
|
13
|
+
"""Validate data against schemas, patterns, and custom rules."""
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
"""Initialize data validator tool."""
|
|
17
|
+
metadata = ToolMetadata(
|
|
18
|
+
name="data_validator",
|
|
19
|
+
description="Validate data types, formats, ranges, and patterns",
|
|
20
|
+
category=ToolCategory.COMPUTATION,
|
|
21
|
+
tags=["validation", "schema", "data", "rules", "constraints"],
|
|
22
|
+
version="1.0.0",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
parameters = [
|
|
26
|
+
ToolParameter(
|
|
27
|
+
name="data",
|
|
28
|
+
type="string",
|
|
29
|
+
description="Data to validate",
|
|
30
|
+
required=True,
|
|
31
|
+
),
|
|
32
|
+
ToolParameter(
|
|
33
|
+
name="validation_type",
|
|
34
|
+
type="string",
|
|
35
|
+
description="Type of validation to perform",
|
|
36
|
+
required=True,
|
|
37
|
+
enum=[
|
|
38
|
+
"email",
|
|
39
|
+
"url",
|
|
40
|
+
"phone",
|
|
41
|
+
"ip",
|
|
42
|
+
"date",
|
|
43
|
+
"number",
|
|
44
|
+
"json",
|
|
45
|
+
"custom_regex",
|
|
46
|
+
],
|
|
47
|
+
),
|
|
48
|
+
ToolParameter(
|
|
49
|
+
name="custom_pattern",
|
|
50
|
+
type="string",
|
|
51
|
+
description="Custom regex pattern (for custom_regex type)",
|
|
52
|
+
required=False,
|
|
53
|
+
),
|
|
54
|
+
ToolParameter(
|
|
55
|
+
name="min_value",
|
|
56
|
+
type="number",
|
|
57
|
+
description="Minimum value (for number validation)",
|
|
58
|
+
required=False,
|
|
59
|
+
),
|
|
60
|
+
ToolParameter(
|
|
61
|
+
name="max_value",
|
|
62
|
+
type="number",
|
|
63
|
+
description="Maximum value (for number validation)",
|
|
64
|
+
required=False,
|
|
65
|
+
),
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
super().__init__(metadata, parameters)
|
|
69
|
+
|
|
70
|
+
async def _execute(
|
|
71
|
+
self,
|
|
72
|
+
data: str,
|
|
73
|
+
validation_type: str,
|
|
74
|
+
custom_pattern: Optional[str] = None,
|
|
75
|
+
min_value: Optional[float] = None,
|
|
76
|
+
max_value: Optional[float] = None,
|
|
77
|
+
) -> Dict[str, Any]:
|
|
78
|
+
"""Execute data validation.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
data: Data to validate
|
|
82
|
+
validation_type: Type of validation
|
|
83
|
+
custom_pattern: Custom regex pattern
|
|
84
|
+
min_value: Minimum value
|
|
85
|
+
max_value: Maximum value
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Dictionary containing validation results
|
|
89
|
+
"""
|
|
90
|
+
result: Dict[str, Any] = {
|
|
91
|
+
"validation_type": validation_type,
|
|
92
|
+
"data": data,
|
|
93
|
+
"valid": False,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
if validation_type == "email":
|
|
98
|
+
result.update(self._validate_email(data))
|
|
99
|
+
|
|
100
|
+
elif validation_type == "url":
|
|
101
|
+
result.update(self._validate_url(data))
|
|
102
|
+
|
|
103
|
+
elif validation_type == "phone":
|
|
104
|
+
result.update(self._validate_phone(data))
|
|
105
|
+
|
|
106
|
+
elif validation_type == "ip":
|
|
107
|
+
result.update(self._validate_ip(data))
|
|
108
|
+
|
|
109
|
+
elif validation_type == "date":
|
|
110
|
+
result.update(self._validate_date(data))
|
|
111
|
+
|
|
112
|
+
elif validation_type == "number":
|
|
113
|
+
result.update(self._validate_number(data, min_value, max_value))
|
|
114
|
+
|
|
115
|
+
elif validation_type == "custom_regex":
|
|
116
|
+
if not custom_pattern:
|
|
117
|
+
raise ValueError("custom_pattern required for custom_regex validation")
|
|
118
|
+
result.update(self._validate_custom_regex(data, custom_pattern))
|
|
119
|
+
|
|
120
|
+
elif validation_type == "json":
|
|
121
|
+
result.update(self._validate_json(data))
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
result["error"] = str(e)
|
|
125
|
+
|
|
126
|
+
logger.info(
|
|
127
|
+
f"Data validation ({validation_type}) completed: valid={result.get('valid', False)}"
|
|
128
|
+
)
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
def _validate_json(self, data: str) -> Dict[str, Any]:
|
|
132
|
+
"""Validate JSON."""
|
|
133
|
+
import json
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
parsed = json.loads(data)
|
|
137
|
+
return {
|
|
138
|
+
"valid": True,
|
|
139
|
+
"format": "json",
|
|
140
|
+
"parsed_type": type(parsed).__name__,
|
|
141
|
+
}
|
|
142
|
+
except Exception as e:
|
|
143
|
+
return {
|
|
144
|
+
"valid": False,
|
|
145
|
+
"format": "json",
|
|
146
|
+
"error": f"Invalid JSON: {e}",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
def _validate_email(self, data: str) -> Dict[str, Any]:
|
|
150
|
+
"""Validate email address."""
|
|
151
|
+
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
152
|
+
match = re.match(pattern, data)
|
|
153
|
+
return {
|
|
154
|
+
"valid": bool(match),
|
|
155
|
+
"format": "email",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
def _validate_url(self, data: str) -> Dict[str, Any]:
|
|
159
|
+
"""Validate URL."""
|
|
160
|
+
pattern = r'^https?://[^\s/$.?#].[^\s]*$'
|
|
161
|
+
match = re.match(pattern, data, re.IGNORECASE)
|
|
162
|
+
return {
|
|
163
|
+
"valid": bool(match),
|
|
164
|
+
"format": "url",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
def _validate_phone(self, data: str) -> Dict[str, Any]:
|
|
168
|
+
"""Validate phone number."""
|
|
169
|
+
# Remove common separators
|
|
170
|
+
cleaned = re.sub(r'[\s\-\(\)\.]', '', data)
|
|
171
|
+
# Check if it's all digits and reasonable length
|
|
172
|
+
valid = cleaned.isdigit() and 10 <= len(cleaned) <= 15
|
|
173
|
+
return {
|
|
174
|
+
"valid": valid,
|
|
175
|
+
"format": "phone",
|
|
176
|
+
"cleaned": cleaned if valid else None,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
def _validate_ip(self, data: str) -> Dict[str, Any]:
|
|
180
|
+
"""Validate IP address (IPv4)."""
|
|
181
|
+
pattern = r'^(\d{1,3}\.){3}\d{1,3}$'
|
|
182
|
+
if not re.match(pattern, data):
|
|
183
|
+
return {"valid": False, "format": "ipv4"}
|
|
184
|
+
|
|
185
|
+
# Check each octet is 0-255
|
|
186
|
+
octets = data.split('.')
|
|
187
|
+
valid = all(0 <= int(octet) <= 255 for octet in octets)
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
"valid": valid,
|
|
191
|
+
"format": "ipv4",
|
|
192
|
+
"octets": octets if valid else None,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
def _validate_date(self, data: str) -> Dict[str, Any]:
|
|
196
|
+
"""Validate date format."""
|
|
197
|
+
# Common date patterns
|
|
198
|
+
patterns = [
|
|
199
|
+
(r'^\d{4}-\d{2}-\d{2}$', 'YYYY-MM-DD'),
|
|
200
|
+
(r'^\d{2}/\d{2}/\d{4}$', 'MM/DD/YYYY'),
|
|
201
|
+
(r'^\d{2}-\d{2}-\d{4}$', 'DD-MM-YYYY'),
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
for pattern, format_name in patterns:
|
|
205
|
+
if re.match(pattern, data):
|
|
206
|
+
return {
|
|
207
|
+
"valid": True,
|
|
208
|
+
"format": format_name,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
"valid": False,
|
|
213
|
+
"format": "unknown",
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
def _validate_number(
|
|
217
|
+
self, data: str, min_value: Optional[float], max_value: Optional[float]
|
|
218
|
+
) -> Dict[str, Any]:
|
|
219
|
+
"""Validate number and range."""
|
|
220
|
+
try:
|
|
221
|
+
number = float(data)
|
|
222
|
+
|
|
223
|
+
# Check range
|
|
224
|
+
in_range = True
|
|
225
|
+
if min_value is not None and number < min_value:
|
|
226
|
+
in_range = False
|
|
227
|
+
if max_value is not None and number > max_value:
|
|
228
|
+
in_range = False
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
"valid": in_range,
|
|
232
|
+
"format": "number",
|
|
233
|
+
"value": number,
|
|
234
|
+
"in_range": in_range,
|
|
235
|
+
"is_integer": number.is_integer(),
|
|
236
|
+
}
|
|
237
|
+
except ValueError:
|
|
238
|
+
return {
|
|
239
|
+
"valid": False,
|
|
240
|
+
"format": "number",
|
|
241
|
+
"error": "Not a valid number",
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
def _validate_custom_regex(self, data: str, pattern: str) -> Dict[str, Any]:
|
|
245
|
+
"""Validate against custom regex pattern."""
|
|
246
|
+
try:
|
|
247
|
+
match = re.match(pattern, data)
|
|
248
|
+
return {
|
|
249
|
+
"valid": bool(match),
|
|
250
|
+
"format": "custom_regex",
|
|
251
|
+
"pattern": pattern,
|
|
252
|
+
"matched": match.group(0) if match else None,
|
|
253
|
+
}
|
|
254
|
+
except re.error as e:
|
|
255
|
+
return {
|
|
256
|
+
"valid": False,
|
|
257
|
+
"format": "custom_regex",
|
|
258
|
+
"error": f"Invalid regex pattern: {str(e)}",
|
|
259
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Hash generator tool for creating cryptographic hashes."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
import logging
|
|
5
|
+
import hashlib
|
|
6
|
+
import hmac
|
|
7
|
+
import base64
|
|
8
|
+
|
|
9
|
+
from genxai.tools.base import Tool, ToolMetadata, ToolParameter, ToolCategory
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HashGeneratorTool(Tool):
|
|
15
|
+
"""Generate cryptographic hashes and HMACs."""
|
|
16
|
+
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
"""Initialize hash generator tool."""
|
|
19
|
+
metadata = ToolMetadata(
|
|
20
|
+
name="hash_generator",
|
|
21
|
+
description="Generate cryptographic hashes (MD5, SHA1, SHA256, SHA512) and HMACs",
|
|
22
|
+
category=ToolCategory.COMPUTATION,
|
|
23
|
+
tags=["hash", "crypto", "md5", "sha", "hmac", "checksum"],
|
|
24
|
+
version="1.0.0",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
parameters = [
|
|
28
|
+
ToolParameter(
|
|
29
|
+
name="data",
|
|
30
|
+
type="string",
|
|
31
|
+
description="Data to hash",
|
|
32
|
+
required=True,
|
|
33
|
+
),
|
|
34
|
+
ToolParameter(
|
|
35
|
+
name="algorithm",
|
|
36
|
+
type="string",
|
|
37
|
+
description="Hash algorithm",
|
|
38
|
+
required=True,
|
|
39
|
+
enum=["md5", "sha1", "sha256", "sha512", "sha3_256", "sha3_512", "blake2b", "blake2s"],
|
|
40
|
+
),
|
|
41
|
+
ToolParameter(
|
|
42
|
+
name="encoding",
|
|
43
|
+
type="string",
|
|
44
|
+
description="Input data encoding",
|
|
45
|
+
required=False,
|
|
46
|
+
default="utf-8",
|
|
47
|
+
enum=["utf-8", "ascii", "latin-1"],
|
|
48
|
+
),
|
|
49
|
+
ToolParameter(
|
|
50
|
+
name="output_format",
|
|
51
|
+
type="string",
|
|
52
|
+
description="Output format",
|
|
53
|
+
required=False,
|
|
54
|
+
default="hex",
|
|
55
|
+
enum=["hex", "base64"],
|
|
56
|
+
),
|
|
57
|
+
ToolParameter(
|
|
58
|
+
name="hmac_key",
|
|
59
|
+
type="string",
|
|
60
|
+
description="HMAC key (if provided, generates HMAC instead of hash)",
|
|
61
|
+
required=False,
|
|
62
|
+
),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
super().__init__(metadata, parameters)
|
|
66
|
+
|
|
67
|
+
async def _execute(
|
|
68
|
+
self,
|
|
69
|
+
data: str,
|
|
70
|
+
algorithm: str,
|
|
71
|
+
encoding: str = "utf-8",
|
|
72
|
+
output_format: str = "hex",
|
|
73
|
+
hmac_key: str = None,
|
|
74
|
+
) -> Dict[str, Any]:
|
|
75
|
+
"""Execute hash generation.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
data: Data to hash
|
|
79
|
+
algorithm: Hash algorithm
|
|
80
|
+
encoding: Input encoding
|
|
81
|
+
output_format: Output format
|
|
82
|
+
hmac_key: HMAC key (optional)
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Dictionary containing hash results
|
|
86
|
+
"""
|
|
87
|
+
result: Dict[str, Any] = {
|
|
88
|
+
"algorithm": algorithm,
|
|
89
|
+
"output_format": output_format,
|
|
90
|
+
"success": False,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
# Encode data
|
|
95
|
+
data_bytes = data.encode(encoding)
|
|
96
|
+
|
|
97
|
+
# Generate hash or HMAC
|
|
98
|
+
if hmac_key:
|
|
99
|
+
# Generate HMAC
|
|
100
|
+
key_bytes = hmac_key.encode(encoding)
|
|
101
|
+
hash_obj = hmac.new(key_bytes, data_bytes, algorithm)
|
|
102
|
+
result["type"] = "hmac"
|
|
103
|
+
else:
|
|
104
|
+
# Generate regular hash
|
|
105
|
+
hash_obj = hashlib.new(algorithm, data_bytes)
|
|
106
|
+
result["type"] = "hash"
|
|
107
|
+
|
|
108
|
+
# Format output
|
|
109
|
+
if output_format == "hex":
|
|
110
|
+
hash_value = hash_obj.hexdigest()
|
|
111
|
+
elif output_format == "base64":
|
|
112
|
+
hash_value = base64.b64encode(hash_obj.digest()).decode("ascii")
|
|
113
|
+
else:
|
|
114
|
+
hash_value = hash_obj.hexdigest()
|
|
115
|
+
|
|
116
|
+
result.update({
|
|
117
|
+
"hash": hash_value,
|
|
118
|
+
"length": len(hash_value),
|
|
119
|
+
"input_length": len(data),
|
|
120
|
+
"success": True,
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
except ValueError as e:
|
|
124
|
+
result["error"] = f"Invalid algorithm: {str(e)}"
|
|
125
|
+
except Exception as e:
|
|
126
|
+
result["error"] = str(e)
|
|
127
|
+
|
|
128
|
+
logger.info(f"Hash generation ({algorithm}) completed: success={result['success']}")
|
|
129
|
+
return result
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Regex matcher tool for pattern matching and extraction."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
import logging
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
from genxai.tools.base import Tool, ToolMetadata, ToolParameter, ToolCategory
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RegexMatcherTool(Tool):
|
|
13
|
+
"""Match, search, and extract patterns using regular expressions."""
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
"""Initialize regex matcher tool."""
|
|
17
|
+
metadata = ToolMetadata(
|
|
18
|
+
name="regex_matcher",
|
|
19
|
+
description="Match, search, and extract patterns using regular expressions",
|
|
20
|
+
category=ToolCategory.COMPUTATION,
|
|
21
|
+
tags=["regex", "pattern", "matching", "extraction", "search"],
|
|
22
|
+
version="1.0.0",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
parameters = [
|
|
26
|
+
ToolParameter(
|
|
27
|
+
name="text",
|
|
28
|
+
type="string",
|
|
29
|
+
description="Text to search in",
|
|
30
|
+
required=True,
|
|
31
|
+
),
|
|
32
|
+
ToolParameter(
|
|
33
|
+
name="pattern",
|
|
34
|
+
type="string",
|
|
35
|
+
description="Regular expression pattern",
|
|
36
|
+
required=True,
|
|
37
|
+
),
|
|
38
|
+
ToolParameter(
|
|
39
|
+
name="operation",
|
|
40
|
+
type="string",
|
|
41
|
+
description="Operation to perform",
|
|
42
|
+
required=False,
|
|
43
|
+
default="findall",
|
|
44
|
+
enum=["match", "search", "findall", "finditer", "sub", "split"],
|
|
45
|
+
),
|
|
46
|
+
ToolParameter(
|
|
47
|
+
name="replacement",
|
|
48
|
+
type="string",
|
|
49
|
+
description="Replacement string (for sub operation)",
|
|
50
|
+
required=False,
|
|
51
|
+
),
|
|
52
|
+
ToolParameter(
|
|
53
|
+
name="flags",
|
|
54
|
+
type="string",
|
|
55
|
+
description="Regex flags (comma-separated: IGNORECASE,MULTILINE,DOTALL)",
|
|
56
|
+
required=False,
|
|
57
|
+
),
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
super().__init__(metadata, parameters)
|
|
61
|
+
|
|
62
|
+
async def _execute(
|
|
63
|
+
self,
|
|
64
|
+
text: str,
|
|
65
|
+
pattern: str,
|
|
66
|
+
operation: str = "findall",
|
|
67
|
+
replacement: Optional[str] = None,
|
|
68
|
+
flags: Optional[str] = None,
|
|
69
|
+
) -> Dict[str, Any]:
|
|
70
|
+
"""Execute regex operation.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
text: Text to search
|
|
74
|
+
pattern: Regex pattern
|
|
75
|
+
operation: Operation to perform
|
|
76
|
+
replacement: Replacement string
|
|
77
|
+
flags: Regex flags
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Dictionary containing operation results
|
|
81
|
+
"""
|
|
82
|
+
result: Dict[str, Any] = {
|
|
83
|
+
"operation": operation,
|
|
84
|
+
"pattern": pattern,
|
|
85
|
+
"success": False,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
# Parse flags
|
|
90
|
+
regex_flags = self._parse_flags(flags)
|
|
91
|
+
|
|
92
|
+
# Compile pattern
|
|
93
|
+
compiled_pattern = re.compile(pattern, regex_flags)
|
|
94
|
+
|
|
95
|
+
if operation == "match":
|
|
96
|
+
match = compiled_pattern.match(text)
|
|
97
|
+
if match:
|
|
98
|
+
result.update({
|
|
99
|
+
"matched": True,
|
|
100
|
+
"match": match.group(0),
|
|
101
|
+
"groups": match.groups(),
|
|
102
|
+
"groupdict": match.groupdict(),
|
|
103
|
+
"span": match.span(),
|
|
104
|
+
})
|
|
105
|
+
else:
|
|
106
|
+
result["matched"] = False
|
|
107
|
+
|
|
108
|
+
elif operation == "search":
|
|
109
|
+
match = compiled_pattern.search(text)
|
|
110
|
+
if match:
|
|
111
|
+
result.update({
|
|
112
|
+
"found": True,
|
|
113
|
+
"match": match.group(0),
|
|
114
|
+
"groups": match.groups(),
|
|
115
|
+
"groupdict": match.groupdict(),
|
|
116
|
+
"span": match.span(),
|
|
117
|
+
})
|
|
118
|
+
else:
|
|
119
|
+
result["found"] = False
|
|
120
|
+
|
|
121
|
+
elif operation == "findall":
|
|
122
|
+
matches = compiled_pattern.findall(text)
|
|
123
|
+
result.update({
|
|
124
|
+
"matches": matches,
|
|
125
|
+
"count": len(matches),
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
elif operation == "finditer":
|
|
129
|
+
matches = []
|
|
130
|
+
for match in compiled_pattern.finditer(text):
|
|
131
|
+
matches.append({
|
|
132
|
+
"match": match.group(0),
|
|
133
|
+
"groups": match.groups(),
|
|
134
|
+
"groupdict": match.groupdict(),
|
|
135
|
+
"span": match.span(),
|
|
136
|
+
})
|
|
137
|
+
result.update({
|
|
138
|
+
"matches": matches,
|
|
139
|
+
"count": len(matches),
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
elif operation == "sub":
|
|
143
|
+
if replacement is None:
|
|
144
|
+
raise ValueError("replacement parameter required for sub operation")
|
|
145
|
+
|
|
146
|
+
new_text = compiled_pattern.sub(replacement, text)
|
|
147
|
+
result.update({
|
|
148
|
+
"original_text": text,
|
|
149
|
+
"new_text": new_text,
|
|
150
|
+
"replacements_made": text != new_text,
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
elif operation == "split":
|
|
154
|
+
parts = compiled_pattern.split(text)
|
|
155
|
+
result.update({
|
|
156
|
+
"parts": parts,
|
|
157
|
+
"count": len(parts),
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
result["success"] = True
|
|
161
|
+
|
|
162
|
+
except re.error as e:
|
|
163
|
+
result["error"] = f"Invalid regex pattern: {str(e)}"
|
|
164
|
+
except Exception as e:
|
|
165
|
+
result["error"] = str(e)
|
|
166
|
+
|
|
167
|
+
logger.info(f"Regex {operation} completed: success={result['success']}")
|
|
168
|
+
return result
|
|
169
|
+
|
|
170
|
+
def _parse_flags(self, flags: Optional[str]) -> int:
|
|
171
|
+
"""Parse regex flags from string.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
flags: Comma-separated flag names
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
Combined regex flags
|
|
178
|
+
"""
|
|
179
|
+
if not flags:
|
|
180
|
+
return 0
|
|
181
|
+
|
|
182
|
+
flag_map = {
|
|
183
|
+
"IGNORECASE": re.IGNORECASE,
|
|
184
|
+
"I": re.IGNORECASE,
|
|
185
|
+
"MULTILINE": re.MULTILINE,
|
|
186
|
+
"M": re.MULTILINE,
|
|
187
|
+
"DOTALL": re.DOTALL,
|
|
188
|
+
"S": re.DOTALL,
|
|
189
|
+
"VERBOSE": re.VERBOSE,
|
|
190
|
+
"X": re.VERBOSE,
|
|
191
|
+
"ASCII": re.ASCII,
|
|
192
|
+
"A": re.ASCII,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
combined_flags = 0
|
|
196
|
+
for flag_name in flags.upper().split(","):
|
|
197
|
+
flag_name = flag_name.strip()
|
|
198
|
+
if flag_name in flag_map:
|
|
199
|
+
combined_flags |= flag_map[flag_name]
|
|
200
|
+
|
|
201
|
+
return combined_flags
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Data processing tools for GenXAI."""
|
|
2
|
+
|
|
3
|
+
from genxai.tools.builtin.data.json_processor import JSONProcessorTool
|
|
4
|
+
from genxai.tools.builtin.data.csv_processor import CSVProcessorTool
|
|
5
|
+
from genxai.tools.builtin.data.xml_processor import XMLProcessorTool
|
|
6
|
+
from genxai.tools.builtin.data.data_transformer import DataTransformerTool
|
|
7
|
+
from genxai.tools.builtin.data.text_analyzer import TextAnalyzerTool
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"JSONProcessorTool",
|
|
11
|
+
"CSVProcessorTool",
|
|
12
|
+
"XMLProcessorTool",
|
|
13
|
+
"DataTransformerTool",
|
|
14
|
+
"TextAnalyzerTool",
|
|
15
|
+
]
|