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.
Files changed (156) hide show
  1. cli/__init__.py +3 -0
  2. cli/commands/__init__.py +6 -0
  3. cli/commands/approval.py +85 -0
  4. cli/commands/audit.py +127 -0
  5. cli/commands/metrics.py +25 -0
  6. cli/commands/tool.py +389 -0
  7. cli/main.py +32 -0
  8. genxai/__init__.py +81 -0
  9. genxai/api/__init__.py +5 -0
  10. genxai/api/app.py +21 -0
  11. genxai/config/__init__.py +5 -0
  12. genxai/config/settings.py +37 -0
  13. genxai/connectors/__init__.py +19 -0
  14. genxai/connectors/base.py +122 -0
  15. genxai/connectors/kafka.py +92 -0
  16. genxai/connectors/postgres_cdc.py +95 -0
  17. genxai/connectors/registry.py +44 -0
  18. genxai/connectors/sqs.py +94 -0
  19. genxai/connectors/webhook.py +73 -0
  20. genxai/core/__init__.py +37 -0
  21. genxai/core/agent/__init__.py +32 -0
  22. genxai/core/agent/base.py +206 -0
  23. genxai/core/agent/config_io.py +59 -0
  24. genxai/core/agent/registry.py +98 -0
  25. genxai/core/agent/runtime.py +970 -0
  26. genxai/core/communication/__init__.py +6 -0
  27. genxai/core/communication/collaboration.py +44 -0
  28. genxai/core/communication/message_bus.py +192 -0
  29. genxai/core/communication/protocols.py +35 -0
  30. genxai/core/execution/__init__.py +22 -0
  31. genxai/core/execution/metadata.py +181 -0
  32. genxai/core/execution/queue.py +201 -0
  33. genxai/core/graph/__init__.py +30 -0
  34. genxai/core/graph/checkpoints.py +77 -0
  35. genxai/core/graph/edges.py +131 -0
  36. genxai/core/graph/engine.py +813 -0
  37. genxai/core/graph/executor.py +516 -0
  38. genxai/core/graph/nodes.py +161 -0
  39. genxai/core/graph/trigger_runner.py +40 -0
  40. genxai/core/memory/__init__.py +19 -0
  41. genxai/core/memory/base.py +72 -0
  42. genxai/core/memory/embedding.py +327 -0
  43. genxai/core/memory/episodic.py +448 -0
  44. genxai/core/memory/long_term.py +467 -0
  45. genxai/core/memory/manager.py +543 -0
  46. genxai/core/memory/persistence.py +297 -0
  47. genxai/core/memory/procedural.py +461 -0
  48. genxai/core/memory/semantic.py +526 -0
  49. genxai/core/memory/shared.py +62 -0
  50. genxai/core/memory/short_term.py +303 -0
  51. genxai/core/memory/vector_store.py +508 -0
  52. genxai/core/memory/working.py +211 -0
  53. genxai/core/state/__init__.py +6 -0
  54. genxai/core/state/manager.py +293 -0
  55. genxai/core/state/schema.py +115 -0
  56. genxai/llm/__init__.py +14 -0
  57. genxai/llm/base.py +150 -0
  58. genxai/llm/factory.py +329 -0
  59. genxai/llm/providers/__init__.py +1 -0
  60. genxai/llm/providers/anthropic.py +249 -0
  61. genxai/llm/providers/cohere.py +274 -0
  62. genxai/llm/providers/google.py +334 -0
  63. genxai/llm/providers/ollama.py +147 -0
  64. genxai/llm/providers/openai.py +257 -0
  65. genxai/llm/routing.py +83 -0
  66. genxai/observability/__init__.py +6 -0
  67. genxai/observability/logging.py +327 -0
  68. genxai/observability/metrics.py +494 -0
  69. genxai/observability/tracing.py +372 -0
  70. genxai/performance/__init__.py +39 -0
  71. genxai/performance/cache.py +256 -0
  72. genxai/performance/pooling.py +289 -0
  73. genxai/security/audit.py +304 -0
  74. genxai/security/auth.py +315 -0
  75. genxai/security/cost_control.py +528 -0
  76. genxai/security/default_policies.py +44 -0
  77. genxai/security/jwt.py +142 -0
  78. genxai/security/oauth.py +226 -0
  79. genxai/security/pii.py +366 -0
  80. genxai/security/policy_engine.py +82 -0
  81. genxai/security/rate_limit.py +341 -0
  82. genxai/security/rbac.py +247 -0
  83. genxai/security/validation.py +218 -0
  84. genxai/tools/__init__.py +21 -0
  85. genxai/tools/base.py +383 -0
  86. genxai/tools/builtin/__init__.py +131 -0
  87. genxai/tools/builtin/communication/__init__.py +15 -0
  88. genxai/tools/builtin/communication/email_sender.py +159 -0
  89. genxai/tools/builtin/communication/notification_manager.py +167 -0
  90. genxai/tools/builtin/communication/slack_notifier.py +118 -0
  91. genxai/tools/builtin/communication/sms_sender.py +118 -0
  92. genxai/tools/builtin/communication/webhook_caller.py +136 -0
  93. genxai/tools/builtin/computation/__init__.py +15 -0
  94. genxai/tools/builtin/computation/calculator.py +101 -0
  95. genxai/tools/builtin/computation/code_executor.py +183 -0
  96. genxai/tools/builtin/computation/data_validator.py +259 -0
  97. genxai/tools/builtin/computation/hash_generator.py +129 -0
  98. genxai/tools/builtin/computation/regex_matcher.py +201 -0
  99. genxai/tools/builtin/data/__init__.py +15 -0
  100. genxai/tools/builtin/data/csv_processor.py +213 -0
  101. genxai/tools/builtin/data/data_transformer.py +299 -0
  102. genxai/tools/builtin/data/json_processor.py +233 -0
  103. genxai/tools/builtin/data/text_analyzer.py +288 -0
  104. genxai/tools/builtin/data/xml_processor.py +175 -0
  105. genxai/tools/builtin/database/__init__.py +15 -0
  106. genxai/tools/builtin/database/database_inspector.py +157 -0
  107. genxai/tools/builtin/database/mongodb_query.py +196 -0
  108. genxai/tools/builtin/database/redis_cache.py +167 -0
  109. genxai/tools/builtin/database/sql_query.py +145 -0
  110. genxai/tools/builtin/database/vector_search.py +163 -0
  111. genxai/tools/builtin/file/__init__.py +17 -0
  112. genxai/tools/builtin/file/directory_scanner.py +214 -0
  113. genxai/tools/builtin/file/file_compressor.py +237 -0
  114. genxai/tools/builtin/file/file_reader.py +102 -0
  115. genxai/tools/builtin/file/file_writer.py +122 -0
  116. genxai/tools/builtin/file/image_processor.py +186 -0
  117. genxai/tools/builtin/file/pdf_parser.py +144 -0
  118. genxai/tools/builtin/test/__init__.py +15 -0
  119. genxai/tools/builtin/test/async_simulator.py +62 -0
  120. genxai/tools/builtin/test/data_transformer.py +99 -0
  121. genxai/tools/builtin/test/error_generator.py +82 -0
  122. genxai/tools/builtin/test/simple_math.py +94 -0
  123. genxai/tools/builtin/test/string_processor.py +72 -0
  124. genxai/tools/builtin/web/__init__.py +15 -0
  125. genxai/tools/builtin/web/api_caller.py +161 -0
  126. genxai/tools/builtin/web/html_parser.py +330 -0
  127. genxai/tools/builtin/web/http_client.py +187 -0
  128. genxai/tools/builtin/web/url_validator.py +162 -0
  129. genxai/tools/builtin/web/web_scraper.py +170 -0
  130. genxai/tools/custom/my_test_tool_2.py +9 -0
  131. genxai/tools/dynamic.py +105 -0
  132. genxai/tools/mcp_server.py +167 -0
  133. genxai/tools/persistence/__init__.py +6 -0
  134. genxai/tools/persistence/models.py +55 -0
  135. genxai/tools/persistence/service.py +322 -0
  136. genxai/tools/registry.py +227 -0
  137. genxai/tools/security/__init__.py +11 -0
  138. genxai/tools/security/limits.py +214 -0
  139. genxai/tools/security/policy.py +20 -0
  140. genxai/tools/security/sandbox.py +248 -0
  141. genxai/tools/templates.py +435 -0
  142. genxai/triggers/__init__.py +19 -0
  143. genxai/triggers/base.py +104 -0
  144. genxai/triggers/file_watcher.py +75 -0
  145. genxai/triggers/queue.py +68 -0
  146. genxai/triggers/registry.py +82 -0
  147. genxai/triggers/schedule.py +66 -0
  148. genxai/triggers/webhook.py +68 -0
  149. genxai/utils/__init__.py +1 -0
  150. genxai/utils/tokens.py +295 -0
  151. genxai_framework-0.1.0.dist-info/METADATA +495 -0
  152. genxai_framework-0.1.0.dist-info/RECORD +156 -0
  153. genxai_framework-0.1.0.dist-info/WHEEL +5 -0
  154. genxai_framework-0.1.0.dist-info/entry_points.txt +2 -0
  155. genxai_framework-0.1.0.dist-info/licenses/LICENSE +21 -0
  156. genxai_framework-0.1.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,170 @@
1
+ """Web scraper tool for extracting content from web pages."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+ import logging
5
+ import asyncio
6
+ from urllib.parse import urljoin, urlparse
7
+
8
+ from genxai.tools.base import Tool, ToolMetadata, ToolParameter, ToolCategory
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class WebScraperTool(Tool):
14
+ """Extract content from web pages using BeautifulSoup."""
15
+
16
+ def __init__(self) -> None:
17
+ """Initialize web scraper tool."""
18
+ metadata = ToolMetadata(
19
+ name="web_scraper",
20
+ description="Extract content, text, and links from web pages",
21
+ category=ToolCategory.WEB,
22
+ tags=["scraping", "web", "extraction", "html", "parsing"],
23
+ version="1.0.0",
24
+ )
25
+
26
+ parameters = [
27
+ ToolParameter(
28
+ name="url",
29
+ type="string",
30
+ description="URL of the web page to scrape",
31
+ required=True,
32
+ pattern=r"^https?://",
33
+ ),
34
+ ToolParameter(
35
+ name="selector",
36
+ type="string",
37
+ description="CSS selector to extract specific content (optional)",
38
+ required=False,
39
+ ),
40
+ ToolParameter(
41
+ name="extract_links",
42
+ type="boolean",
43
+ description="Whether to extract all links from the page",
44
+ required=False,
45
+ default=False,
46
+ ),
47
+ ToolParameter(
48
+ name="extract_images",
49
+ type="boolean",
50
+ description="Whether to extract all image URLs",
51
+ required=False,
52
+ default=False,
53
+ ),
54
+ ToolParameter(
55
+ name="timeout",
56
+ type="number",
57
+ description="Request timeout in seconds",
58
+ required=False,
59
+ default=30,
60
+ min_value=1,
61
+ max_value=120,
62
+ ),
63
+ ]
64
+
65
+ super().__init__(metadata, parameters)
66
+
67
+ async def _execute(
68
+ self,
69
+ url: str,
70
+ selector: Optional[str] = None,
71
+ extract_links: bool = False,
72
+ extract_images: bool = False,
73
+ timeout: int = 30,
74
+ ) -> Dict[str, Any]:
75
+ """Execute web scraping.
76
+
77
+ Args:
78
+ url: URL to scrape
79
+ selector: CSS selector for specific content
80
+ extract_links: Whether to extract links
81
+ extract_images: Whether to extract images
82
+ timeout: Request timeout
83
+
84
+ Returns:
85
+ Dictionary containing scraped content
86
+ """
87
+ try:
88
+ import httpx
89
+ from bs4 import BeautifulSoup
90
+ except ImportError as e:
91
+ raise ImportError(
92
+ f"Required package not installed: {e}. "
93
+ "Install with: pip install httpx beautifulsoup4"
94
+ )
95
+
96
+ # Validate URL
97
+ parsed = urlparse(url)
98
+ if not parsed.scheme or not parsed.netloc:
99
+ raise ValueError(f"Invalid URL: {url}")
100
+
101
+ # Fetch page content
102
+ async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
103
+ response = await client.get(url)
104
+ response.raise_for_status()
105
+ html_content = response.text
106
+
107
+ # Parse HTML
108
+ soup = BeautifulSoup(html_content, "html.parser")
109
+
110
+ result: Dict[str, Any] = {
111
+ "url": url,
112
+ "title": soup.title.string if soup.title else None,
113
+ "status_code": response.status_code,
114
+ }
115
+
116
+ # Extract specific content with selector
117
+ if selector:
118
+ elements = soup.select(selector)
119
+ result["selected_content"] = [
120
+ {"text": elem.get_text(strip=True), "html": str(elem)} for elem in elements
121
+ ]
122
+ result["selected_count"] = len(elements)
123
+ else:
124
+ # Extract all text content
125
+ result["text"] = soup.get_text(separator="\n", strip=True)
126
+
127
+ # Extract links
128
+ if extract_links:
129
+ links = []
130
+ for link in soup.find_all("a", href=True):
131
+ href = link["href"]
132
+ absolute_url = urljoin(url, href)
133
+ links.append(
134
+ {
135
+ "text": link.get_text(strip=True),
136
+ "href": absolute_url,
137
+ "title": link.get("title"),
138
+ }
139
+ )
140
+ result["links"] = links
141
+ result["links_count"] = len(links)
142
+
143
+ # Extract images
144
+ if extract_images:
145
+ images = []
146
+ for img in soup.find_all("img"):
147
+ src = img.get("src")
148
+ if src:
149
+ absolute_url = urljoin(url, src)
150
+ images.append(
151
+ {
152
+ "src": absolute_url,
153
+ "alt": img.get("alt"),
154
+ "title": img.get("title"),
155
+ }
156
+ )
157
+ result["images"] = images
158
+ result["images_count"] = len(images)
159
+
160
+ # Extract metadata
161
+ meta_tags = {}
162
+ for meta in soup.find_all("meta"):
163
+ name = meta.get("name") or meta.get("property")
164
+ content = meta.get("content")
165
+ if name and content:
166
+ meta_tags[name] = content
167
+ result["metadata"] = meta_tags
168
+
169
+ logger.info(f"Successfully scraped {url}")
170
+ return result
@@ -0,0 +1,9 @@
1
+ """
2
+ Auto-generated tool: my_test_tool_2
3
+ Description: test tool
4
+ Category: custom
5
+ Created: 2026-01-29 20:36:41.350610
6
+ """
7
+
8
+ # Tool code
9
+ result = {'ok': True, 'params': params}
@@ -0,0 +1,105 @@
1
+ """Dynamic tool creation from Python code."""
2
+
3
+ from typing import Any, Dict
4
+ import logging
5
+ from genxai.tools.base import Tool, ToolMetadata, ToolParameter
6
+ from genxai.tools.security import SafeExecutor, ExecutionTimeout
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class DynamicTool(Tool):
12
+ """Tool created dynamically from Python code with security sandboxing."""
13
+
14
+ def __init__(
15
+ self,
16
+ metadata: ToolMetadata,
17
+ parameters: list[ToolParameter],
18
+ code: str,
19
+ timeout: int = 30
20
+ ):
21
+ """Initialize dynamic tool.
22
+
23
+ Args:
24
+ metadata: Tool metadata
25
+ parameters: Tool parameters
26
+ code: Python code to execute
27
+ timeout: Maximum execution time in seconds (default: 30)
28
+ """
29
+ super().__init__(metadata, parameters)
30
+ self.code = code
31
+ self.timeout = timeout
32
+ self._compiled_code = None
33
+ self._safe_executor = SafeExecutor(timeout=timeout)
34
+ self._compile_code()
35
+
36
+ def _compile_code(self) -> None:
37
+ """Compile the Python code for execution with security checks."""
38
+ try:
39
+ # Use SafeExecutor for secure compilation
40
+ self._compiled_code = self._safe_executor.compile_code(
41
+ self.code,
42
+ f'<dynamic:{self.metadata.name}>'
43
+ )
44
+ logger.info(f"Securely compiled code for tool: {self.metadata.name}")
45
+ except (SyntaxError, ValueError) as e:
46
+ logger.error(f"Failed to compile code for {self.metadata.name}: {e}")
47
+ raise ValueError(f"Invalid Python code: {e}")
48
+
49
+ async def _execute(self, **kwargs: Any) -> Any:
50
+ """Execute the dynamic tool code in a sandboxed environment.
51
+
52
+ Args:
53
+ **kwargs: Tool parameters
54
+
55
+ Returns:
56
+ Tool execution result
57
+ """
58
+ try:
59
+ # Execute with SafeExecutor (includes timeout and sandboxing)
60
+ result = self._safe_executor.execute(
61
+ self._compiled_code,
62
+ kwargs,
63
+ enable_timeout=True
64
+ )
65
+
66
+ logger.info(f"Dynamic tool {self.metadata.name} executed successfully")
67
+ return result
68
+
69
+ except ExecutionTimeout as e:
70
+ logger.error(f"Dynamic tool {self.metadata.name} timed out: {e}")
71
+ raise RuntimeError(f"Tool execution timed out after {self.timeout} seconds")
72
+ except ValueError as e:
73
+ logger.error(f"Dynamic tool {self.metadata.name} validation failed: {e}")
74
+ raise RuntimeError(f"Tool execution failed: {e}")
75
+ except Exception as e:
76
+ logger.error(f"Dynamic tool {self.metadata.name} execution failed: {e}")
77
+ raise RuntimeError(f"Tool execution failed: {e}")
78
+
79
+ def get_code(self) -> str:
80
+ """Get the tool's source code.
81
+
82
+ Returns:
83
+ Python source code
84
+ """
85
+ return self.code
86
+
87
+ def update_code(self, new_code: str) -> None:
88
+ """Update the tool's code.
89
+
90
+ Args:
91
+ new_code: New Python code
92
+ """
93
+ self.code = new_code
94
+ self._compile_code()
95
+ logger.info(f"Updated code for tool: {self.metadata.name}")
96
+
97
+ def set_timeout(self, timeout: int) -> None:
98
+ """Update the execution timeout.
99
+
100
+ Args:
101
+ timeout: New timeout in seconds
102
+ """
103
+ self.timeout = timeout
104
+ self._safe_executor = SafeExecutor(timeout=timeout)
105
+ logger.info(f"Updated timeout for tool {self.metadata.name}: {timeout}s")
@@ -0,0 +1,167 @@
1
+ """MCP (Model Context Protocol) server for GenXAI tools.
2
+
3
+ This module provides an MCP server that exposes GenXAI tools to external
4
+ applications like Claude Desktop, IDEs, and other AI systems.
5
+ """
6
+
7
+ import asyncio
8
+ import logging
9
+ from typing import Any, Dict, List, Optional
10
+ from mcp.server import Server
11
+ from mcp.server.stdio import stdio_server
12
+ from mcp.types import Tool as MCPTool, TextContent, CallToolResult
13
+
14
+ from genxai.tools.registry import ToolRegistry
15
+ from genxai.tools.base import Tool, ToolCategory
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class GenXAIMCPServer:
21
+ """MCP server for GenXAI tools."""
22
+
23
+ def __init__(self, name: str = "genxai-tools"):
24
+ """Initialize MCP server.
25
+
26
+ Args:
27
+ name: Server name
28
+ """
29
+ self.server = Server(name)
30
+ self._setup_handlers()
31
+
32
+ def _setup_handlers(self) -> None:
33
+ """Setup MCP server handlers."""
34
+
35
+ @self.server.list_tools()
36
+ async def list_tools() -> List[MCPTool]:
37
+ """List all available GenXAI tools."""
38
+ tools = ToolRegistry.list_all()
39
+ mcp_tools = []
40
+
41
+ for tool in tools:
42
+ mcp_tool = self._convert_to_mcp_tool(tool)
43
+ mcp_tools.append(mcp_tool)
44
+
45
+ logger.info(f"Listed {len(mcp_tools)} tools via MCP")
46
+ return mcp_tools
47
+
48
+ @self.server.call_tool()
49
+ async def call_tool(name: str, arguments: Dict[str, Any]) -> CallToolResult:
50
+ """Execute a GenXAI tool.
51
+
52
+ Args:
53
+ name: Tool name
54
+ arguments: Tool arguments
55
+
56
+ Returns:
57
+ Tool execution result
58
+ """
59
+ logger.info(f"MCP tool call: {name} with args: {arguments}")
60
+
61
+ # Get tool from registry
62
+ tool = ToolRegistry.get(name)
63
+ if not tool:
64
+ error_msg = f"Tool '{name}' not found"
65
+ logger.error(error_msg)
66
+ return CallToolResult(
67
+ content=[TextContent(type="text", text=error_msg)],
68
+ isError=True,
69
+ )
70
+
71
+ try:
72
+ # Execute tool
73
+ result = await tool.execute(**arguments)
74
+
75
+ if result.success:
76
+ # Format successful result
77
+ content = self._format_tool_result(result.data)
78
+ return CallToolResult(
79
+ content=[TextContent(type="text", text=content)],
80
+ isError=False,
81
+ )
82
+ else:
83
+ # Format error result
84
+ error_msg = result.error or "Tool execution failed"
85
+ logger.error(f"Tool {name} failed: {error_msg}")
86
+ return CallToolResult(
87
+ content=[TextContent(type="text", text=error_msg)],
88
+ isError=True,
89
+ )
90
+
91
+ except Exception as e:
92
+ error_msg = f"Tool execution error: {str(e)}"
93
+ logger.error(error_msg)
94
+ return CallToolResult(
95
+ content=[TextContent(type="text", text=error_msg)],
96
+ isError=True,
97
+ )
98
+
99
+ def _convert_to_mcp_tool(self, tool: Tool) -> MCPTool:
100
+ """Convert GenXAI tool to MCP tool format.
101
+
102
+ Args:
103
+ tool: GenXAI tool
104
+
105
+ Returns:
106
+ MCP tool definition
107
+ """
108
+ schema = tool.get_schema()
109
+
110
+ return MCPTool(
111
+ name=tool.metadata.name,
112
+ description=tool.metadata.description,
113
+ inputSchema={
114
+ "type": "object",
115
+ "properties": schema["parameters"]["properties"],
116
+ "required": schema["parameters"].get("required", []),
117
+ },
118
+ )
119
+
120
+ def _format_tool_result(self, data: Any) -> str:
121
+ """Format tool result for MCP response.
122
+
123
+ Args:
124
+ data: Tool result data
125
+
126
+ Returns:
127
+ Formatted string
128
+ """
129
+ import json
130
+
131
+ if isinstance(data, (dict, list)):
132
+ return json.dumps(data, indent=2)
133
+ return str(data)
134
+
135
+ async def run(self) -> None:
136
+ """Run the MCP server."""
137
+ logger.info("Starting GenXAI MCP server...")
138
+ async with stdio_server() as (read_stream, write_stream):
139
+ await self.server.run(
140
+ read_stream,
141
+ write_stream,
142
+ self.server.create_initialization_options(),
143
+ )
144
+
145
+
146
+ async def main():
147
+ """Main entry point for MCP server."""
148
+ # Setup logging
149
+ logging.basicConfig(
150
+ level=logging.INFO,
151
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
152
+ )
153
+
154
+ # Register built-in tools
155
+ from genxai.tools.builtin.computation.calculator import CalculatorTool
156
+ from genxai.tools.builtin.file.file_reader import FileReaderTool
157
+
158
+ ToolRegistry.register(CalculatorTool())
159
+ ToolRegistry.register(FileReaderTool())
160
+
161
+ # Create and run server
162
+ server = GenXAIMCPServer()
163
+ await server.run()
164
+
165
+
166
+ if __name__ == "__main__":
167
+ asyncio.run(main())
@@ -0,0 +1,6 @@
1
+ """Tool persistence module for GenXAI."""
2
+
3
+ from genxai.tools.persistence.models import Base, ToolModel
4
+ from genxai.tools.persistence.service import ToolService
5
+
6
+ __all__ = ["Base", "ToolModel", "ToolService"]
@@ -0,0 +1,55 @@
1
+ """Database models for tools."""
2
+
3
+ from sqlalchemy import Column, Integer, String, Text, JSON, DateTime
4
+ from sqlalchemy.orm import declarative_base
5
+ from datetime import datetime
6
+
7
+ Base = declarative_base()
8
+
9
+
10
+ class ToolModel(Base):
11
+ """Database model for tools."""
12
+
13
+ __tablename__ = "tools"
14
+
15
+ id = Column(Integer, primary_key=True, index=True)
16
+ name = Column(String, unique=True, index=True, nullable=False)
17
+ description = Column(Text, nullable=False)
18
+ category = Column(String, nullable=False)
19
+ tags = Column(JSON, default=[])
20
+ version = Column(String, default="1.0.0")
21
+ author = Column(String, default="GenXAI User")
22
+
23
+ # Tool type: "code_based" or "template_based"
24
+ tool_type = Column(String, nullable=False)
25
+
26
+ # For code-based tools
27
+ code = Column(Text, nullable=True)
28
+ parameters = Column(JSON, default=[])
29
+
30
+ # For template-based tools
31
+ template_name = Column(String, nullable=True)
32
+ template_config = Column(JSON, nullable=True)
33
+
34
+ # Timestamps
35
+ created_at = Column(DateTime, default=datetime.utcnow)
36
+ updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
37
+
38
+ def to_dict(self):
39
+ """Convert model to dictionary."""
40
+ return {
41
+ "id": self.id,
42
+ "name": self.name,
43
+ "description": self.description,
44
+ "category": self.category,
45
+ "tags": self.tags,
46
+ "version": self.version,
47
+ "author": self.author,
48
+ "tool_type": self.tool_type,
49
+ "code": self.code,
50
+ "parameters": self.parameters,
51
+ "template_name": self.template_name,
52
+ "template_config": self.template_config,
53
+ "created_at": self.created_at.isoformat() if self.created_at else None,
54
+ "updated_at": self.updated_at.isoformat() if self.updated_at else None,
55
+ }