kite-agent 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 (61) hide show
  1. kite/__init__.py +46 -0
  2. kite/ab_testing.py +384 -0
  3. kite/agent.py +556 -0
  4. kite/agents/__init__.py +3 -0
  5. kite/agents/plan_execute.py +191 -0
  6. kite/agents/react_agent.py +509 -0
  7. kite/agents/reflective_agent.py +90 -0
  8. kite/agents/rewoo.py +119 -0
  9. kite/agents/tot.py +151 -0
  10. kite/conversation.py +125 -0
  11. kite/core.py +974 -0
  12. kite/data_loaders.py +111 -0
  13. kite/embedding_providers.py +372 -0
  14. kite/llm_providers.py +1278 -0
  15. kite/memory/__init__.py +6 -0
  16. kite/memory/advanced_rag.py +333 -0
  17. kite/memory/graph_rag.py +719 -0
  18. kite/memory/session_memory.py +423 -0
  19. kite/memory/vector_memory.py +579 -0
  20. kite/monitoring.py +611 -0
  21. kite/observers.py +107 -0
  22. kite/optimization/__init__.py +9 -0
  23. kite/optimization/resource_router.py +80 -0
  24. kite/persistence.py +42 -0
  25. kite/pipeline/__init__.py +5 -0
  26. kite/pipeline/deterministic_pipeline.py +323 -0
  27. kite/pipeline/reactive_pipeline.py +171 -0
  28. kite/pipeline_manager.py +15 -0
  29. kite/routing/__init__.py +6 -0
  30. kite/routing/aggregator_router.py +325 -0
  31. kite/routing/llm_router.py +149 -0
  32. kite/routing/semantic_router.py +228 -0
  33. kite/safety/__init__.py +6 -0
  34. kite/safety/circuit_breaker.py +360 -0
  35. kite/safety/guardrails.py +82 -0
  36. kite/safety/idempotency_manager.py +304 -0
  37. kite/safety/kill_switch.py +75 -0
  38. kite/tool.py +183 -0
  39. kite/tool_registry.py +87 -0
  40. kite/tools/__init__.py +21 -0
  41. kite/tools/code_execution.py +53 -0
  42. kite/tools/contrib/__init__.py +19 -0
  43. kite/tools/contrib/calculator.py +26 -0
  44. kite/tools/contrib/datetime_utils.py +20 -0
  45. kite/tools/contrib/linkedin.py +428 -0
  46. kite/tools/contrib/web_search.py +30 -0
  47. kite/tools/mcp/__init__.py +31 -0
  48. kite/tools/mcp/database_mcp.py +267 -0
  49. kite/tools/mcp/gdrive_mcp_server.py +503 -0
  50. kite/tools/mcp/gmail_mcp_server.py +601 -0
  51. kite/tools/mcp/postgres_mcp_server.py +490 -0
  52. kite/tools/mcp/slack_mcp_server.py +538 -0
  53. kite/tools/mcp/stripe_mcp_server.py +219 -0
  54. kite/tools/search.py +90 -0
  55. kite/tools/system_tools.py +54 -0
  56. kite/tools_manager.py +27 -0
  57. kite_agent-0.1.0.dist-info/METADATA +621 -0
  58. kite_agent-0.1.0.dist-info/RECORD +61 -0
  59. kite_agent-0.1.0.dist-info/WHEEL +5 -0
  60. kite_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
  61. kite_agent-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,267 @@
1
+ """
2
+ MCP Database Connectors
3
+ Provides Model Context Protocol (MCP) inspired tools for database interaction.
4
+ """
5
+
6
+ import os
7
+ import json
8
+ from typing import Dict, List, Any, Optional
9
+ import sqlite3
10
+ import psycopg2
11
+ import mysql.connector
12
+ import redis
13
+ import asyncio
14
+ from functools import wraps
15
+
16
+ # New Production Connectors
17
+ try:
18
+ from neo4j import GraphDatabase
19
+ except ImportError:
20
+ GraphDatabase = None
21
+ try:
22
+ from cassandra.cluster import Cluster
23
+ from cassandra.auth import PlainTextAuthProvider
24
+ except Exception:
25
+ Cluster = None
26
+ try:
27
+ import boto3
28
+ except ImportError:
29
+ boto3 = None
30
+ try:
31
+ from google.cloud import firestore
32
+ except ImportError:
33
+ firestore = None
34
+
35
+ def safe_execute(timeout_seconds: int = 30):
36
+ """Decorator for safe tool execution with timeouts and error handling."""
37
+ def decorator(func):
38
+ @wraps(func)
39
+ async def wrapper(*args, **kwargs):
40
+ try:
41
+ # Handle both sync and async functions
42
+ if asyncio.iscoroutinefunction(func):
43
+ return await asyncio.wait_for(func(*args, **kwargs), timeout=timeout_seconds)
44
+ else:
45
+ # For sync functions in an async environment
46
+ loop = asyncio.get_event_loop()
47
+ return await asyncio.wait_for(
48
+ loop.run_in_executor(None, lambda: func(*args, **kwargs)),
49
+ timeout=timeout_seconds
50
+ )
51
+ except asyncio.TimeoutError:
52
+ return {"error": f"Database operation timed out after {timeout_seconds}s"}
53
+ except Exception as e:
54
+ return {"error": f"Database error: {str(e)}"}
55
+ return wrapper
56
+ return decorator
57
+
58
+ class DatabaseMCP:
59
+ """
60
+ MCP-style interface for various databases.
61
+ Implements tools for query and schema discovery.
62
+ """
63
+ def __init__(self, config: Optional[Dict] = None):
64
+ self.config = config or {}
65
+ self.conns = {}
66
+
67
+ def _get_pg_conn(self):
68
+ if 'postgres' not in self.conns:
69
+ self.conns['postgres'] = psycopg2.connect(
70
+ dsn=self.config.get('postgres_dsn', os.getenv('POSTGRES_DSN'))
71
+ )
72
+ return self.conns['postgres']
73
+
74
+ def _get_mysql_conn(self):
75
+ if 'mysql' not in self.conns:
76
+ self.conns['mysql'] = mysql.connector.connect(
77
+ host=self.config.get('mysql_host', os.getenv('MYSQL_HOST')),
78
+ user=self.config.get('mysql_user', os.getenv('MYSQL_USER')),
79
+ password=self.config.get('mysql_password', os.getenv('MYSQL_PASSWORD')),
80
+ database=self.config.get('mysql_db', os.getenv('MYSQL_DB'))
81
+ )
82
+ return self.conns['mysql']
83
+
84
+ def _get_sqlite_conn(self):
85
+ if 'sqlite' not in self.conns:
86
+ self.conns['sqlite'] = sqlite3.connect(
87
+ self.config.get('sqlite_db', os.getenv('SQLITE_DB', 'kite.db')),
88
+ check_same_thread=False
89
+ )
90
+ return self.conns['sqlite']
91
+
92
+ def _get_redis_conn(self):
93
+ if 'redis' not in self.conns:
94
+ self.conns['redis'] = redis.Redis(
95
+ host=self.config.get('redis_host', os.getenv('REDIS_HOST', 'localhost')),
96
+ port=self.config.get('redis_port', os.getenv('REDIS_PORT', 6379)),
97
+ db=self.config.get('redis_db', 0),
98
+ decode_responses=True,
99
+ socket_timeout=5,
100
+ retry_on_timeout=True
101
+ )
102
+ return self.conns['redis']
103
+
104
+ def _get_neo4j_conn(self):
105
+ if 'neo4j' not in self.conns:
106
+ if GraphDatabase is None: raise ImportError("neo4j not installed")
107
+ self.conns['neo4j'] = GraphDatabase.driver(
108
+ self.config.get('neo4j_uri', os.getenv('NEO4J_URI')),
109
+ auth=(self.config.get('neo4j_user', os.getenv('NEO4J_USER')),
110
+ self.config.get('neo4j_password', os.getenv('NEO4J_PASSWORD')))
111
+ )
112
+ return self.conns['neo4j']
113
+
114
+ def _get_cassandra_conn(self):
115
+ if 'cassandra' not in self.conns:
116
+ if Cluster is None: raise ImportError("cassandra-driver not installed")
117
+ auth_provider = PlainTextAuthProvider(
118
+ username=self.config.get('cassandra_user', os.getenv('CASSANDRA_USER')),
119
+ password=self.config.get('cassandra_password', os.getenv('CASSANDRA_PASSWORD'))
120
+ )
121
+ self.conns['cassandra'] = Cluster(
122
+ [self.config.get('cassandra_host', os.getenv('CASSANDRA_HOST', 'localhost'))],
123
+ auth_provider=auth_provider
124
+ ).connect()
125
+ return self.conns['cassandra']
126
+
127
+ def _get_dynamodb_resource(self):
128
+ if 'dynamodb' not in self.conns:
129
+ if boto3 is None: raise ImportError("boto3 not installed")
130
+ self.conns['dynamodb'] = boto3.resource(
131
+ 'dynamodb',
132
+ region_name=self.config.get('aws_region', os.getenv('AWS_REGION', 'us-east-1'))
133
+ )
134
+ return self.conns['dynamodb']
135
+
136
+ def _get_firestore_client(self):
137
+ if 'firestore' not in self.conns:
138
+ if firestore is None: raise ImportError("google-cloud-firestore not installed")
139
+ self.conns['firestore'] = firestore.Client()
140
+ return self.conns['firestore']
141
+
142
+
143
+ @safe_execute(timeout_seconds=30)
144
+ def query_postgres(self, sql: str, params: Optional[tuple] = None) -> List[Dict]:
145
+ """Execute a PostgreSQL query and return results."""
146
+ conn = self._get_pg_conn()
147
+ with conn.cursor() as cur:
148
+ cur.execute(sql, params)
149
+ columns = [desc[0] for desc in cur.description]
150
+ return [dict(zip(columns, row)) for row in cur.fetchall()]
151
+
152
+ @safe_execute(timeout_seconds=30)
153
+ def query_sqlite(self, sql: str, params: Optional[tuple] = None) -> List[Dict]:
154
+ """Execute a SQLite query and return results."""
155
+ conn = self._get_sqlite_conn()
156
+ conn.row_factory = sqlite3.Row
157
+ cur = conn.cursor()
158
+ cur.execute(sql, params or ())
159
+ return [dict(row) for row in cur.fetchall()]
160
+
161
+ @safe_execute(timeout_seconds=30)
162
+ def query_mysql(self, sql: str, params: Optional[tuple] = None) -> List[Dict]:
163
+ """Execute a MySQL query and return results."""
164
+ conn = self._get_mysql_conn()
165
+ cur = conn.cursor(dictionary=True)
166
+ cur.execute(sql, params)
167
+ return cur.fetchall()
168
+
169
+ @safe_execute(timeout_seconds=30)
170
+ async def query_mongo(self, collection: str, query: Dict, limit: int = 10) -> List[Dict]:
171
+ """Query a MongoDB collection."""
172
+ from motor.motor_asyncio import AsyncIOMotorClient
173
+ client = AsyncIOMotorClient(self.config.get('mongo_uri', os.getenv('MONGO_URI')))
174
+ db_name = self.config.get('mongo_db', os.getenv('MONGO_DB'))
175
+ results = await client[db_name][collection].find(query).to_list(length=limit)
176
+ return results
177
+
178
+ @safe_execute(timeout_seconds=30)
179
+ def query_neo4j(self, cypher: str, params: Optional[Dict] = None) -> List[Dict]:
180
+ """Execute a Cypher query on Neo4j."""
181
+ driver = self._get_neo4j_conn()
182
+ with driver.session() as session:
183
+ result = session.run(cypher, params or {})
184
+ return [dict(record) for record in result]
185
+
186
+ @safe_execute(timeout_seconds=30)
187
+ def query_cassandra(self, cql: str, params: Optional[tuple] = None) -> List[Dict]:
188
+ """Execute a CQL query on Cassandra."""
189
+ session = self._get_cassandra_conn()
190
+ rows = session.execute(cql, params or ())
191
+ return [dict(row._asdict()) for row in rows]
192
+
193
+ @safe_execute(timeout_seconds=30)
194
+ def query_dynamodb(self, table_name: str, key: Dict) -> Dict:
195
+ """Get an item from DynamoDB."""
196
+ table = self._get_dynamodb_resource().Table(table_name)
197
+ response = table.get_item(Key=key)
198
+ return response.get('Item', {})
199
+
200
+ @safe_execute(timeout_seconds=30)
201
+ def query_firestore(self, collection: str, document: str) -> Dict:
202
+ """Get a document from Firestore."""
203
+ client = self._get_firestore_client()
204
+ doc_ref = client.collection(collection).document(document)
205
+ doc = doc_ref.get()
206
+ return doc.to_dict() if doc.exists else {}
207
+
208
+ def redis_get(self, key: str) -> Optional[str]:
209
+ """Get value from Redis."""
210
+ return self._get_redis_conn().get(key)
211
+
212
+ def redis_set(self, key: str, value: str, ex: int = 3600):
213
+ """Set value in Redis with TTL."""
214
+ self._get_redis_conn().set(key, value, ex=ex)
215
+
216
+ def get_tools(self) -> List[Dict]:
217
+ """Expose methods as Kite tools."""
218
+ return [
219
+ {
220
+ "name": "query_postgres",
221
+ "description": "Execute Read-only SQL queries on PostgreSQL",
222
+ "parameters": {"sql": "string"},
223
+ "func": self.query_postgres
224
+ },
225
+ {
226
+ "name": "query_mysql",
227
+ "description": "Execute Read-only SQL queries on MySQL",
228
+ "parameters": {"sql": "string"},
229
+ "func": self.query_mysql
230
+ },
231
+ {
232
+ "name": "redis_get",
233
+ "description": "Retrieve data from Redis operational cache",
234
+ "parameters": {"key": "string"},
235
+ "func": self.redis_get
236
+ },
237
+ {
238
+ "name": "query_sqlite",
239
+ "description": "Execute Read-only SQL queries on local SQLite database",
240
+ "parameters": {"sql": "string"},
241
+ "func": self.query_sqlite
242
+ },
243
+ {
244
+ "name": "query_neo4j",
245
+ "description": "Execute Cypher queries on Neo4j graph database",
246
+ "parameters": {"cypher": "string"},
247
+ "func": self.query_neo4j
248
+ },
249
+ {
250
+ "name": "query_cassandra",
251
+ "description": "Execute CQL queries on Cassandra database",
252
+ "parameters": {"cql": "string"},
253
+ "func": self.query_cassandra
254
+ },
255
+ {
256
+ "name": "query_dynamodb",
257
+ "description": "Get item from DynamoDB table",
258
+ "parameters": {"table_name": "string", "key": "object"},
259
+ "func": self.query_dynamodb
260
+ },
261
+ {
262
+ "name": "query_firestore",
263
+ "description": "Get document from Firestore collection",
264
+ "parameters": {"collection": "string", "document": "string"},
265
+ "func": self.query_firestore
266
+ }
267
+ ]