agenthink 0.1.22__py3-none-any.whl → 0.1.25__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.
agenthink/connection.py CHANGED
@@ -125,6 +125,17 @@ class DBConnector:
125
125
  logger.info("Added MSSQL connection for database '%s' to connection_object_dict", db_name)
126
126
  except Exception as e:
127
127
  logger.exception("Unable to create connection object for MSSQL secret: %s", e)
128
+ elif datastore_type == "postgresql":
129
+ try:
130
+ connection_object = self.__connect_postgresql(secret)
131
+ if connection_object:
132
+ db_name = secret.get("database_name", "unknown")
133
+ connection_dict = {"database_type": "postgresql", "connection_object": connection_object}
134
+ self.connection_object_dict[f"{db_name}"] = connection_dict
135
+ logger.info("Added PostgreSQL connection for database '%s' to connection_object_dict", db_name)
136
+ except Exception as e:
137
+ logger.exception("Unable to create connection object for PostgreSQL secret: %s", e)
138
+
128
139
  else:
129
140
  logger.warning("Unsupported datastore_type '%s' for key '%s'", datastore_type, cleaned_key)
130
141
 
@@ -180,6 +191,37 @@ class DBConnector:
180
191
  except Exception as e:
181
192
  logger.exception("MS SQL Connection failed: %s", e)
182
193
  return None
194
+
195
+ def __connect_postgresql(self, secret):
196
+ """
197
+ Establish a connection to a PostgreSQL database.
198
+
199
+ Parameters
200
+ ----------
201
+ secret : dict
202
+ Dictionary containing PostgreSQL connection credentials.
203
+
204
+ Returns
205
+ -------
206
+ psycopg2.connection or None
207
+ PostgreSQL connection object if successful, otherwise None.
208
+ """
209
+ config = {
210
+ "host": secret.get("cluster_ip"),
211
+ "port": secret.get("port"),
212
+ "user": secret.get("username"),
213
+ "password": secret.get("password"),
214
+ "database": secret.get("database_name")
215
+ }
216
+
217
+ try:
218
+ conn = psycopg2.connect(**config)
219
+ logger.info("PostgreSQL connection successfully established to database '%s' on host '%s'",
220
+ config["database"], config["host"])
221
+ return conn
222
+ except Exception as e:
223
+ logger.exception("PostgreSQL connection failed: %s", e)
224
+ return None
183
225
 
184
226
  def __sanitize_secret_name(self, secret_name: str) -> str:
185
227
  """
@@ -284,11 +326,27 @@ class DBConnector:
284
326
  finally:
285
327
  if cursor:
286
328
  cursor.close()
329
+
330
+ elif database_type == "postgresql":
331
+ try:
332
+ cursor = database_connection.cursor()
333
+ cursor.execute(query)
334
+ results = cursor.fetchall()
335
+ logger.info("Executed query on PostgreSQL database '%s': %s", db_name, query)
336
+ return results
337
+ except Exception as e:
338
+ logger.exception("Failed to execute query on PostgreSQL database '%s': %s", db_name, e)
339
+ return None
340
+ finally:
341
+ if cursor:
342
+ cursor.close()
287
343
 
288
344
  else:
289
345
  logger.error("Unsupported database type '%s' for database '%s'", database_type, db_name)
290
346
  return None
291
347
 
348
+
349
+
292
350
  def display_tables(self,db_name:str):
293
351
  """
294
352
  Retrieve a list of user tables from a MySQL or MSSQL database.
@@ -334,6 +392,22 @@ class DBConnector:
334
392
  logger.exception("Failed to retrieve tables from MSSQL database '%s': %s", db_name, e)
335
393
  return None
336
394
 
395
+ elif database_type == "postgresql":
396
+ try:
397
+ cursor = database_connection.cursor()
398
+ cursor.execute("""
399
+ SELECT table_name
400
+ FROM information_schema.tables
401
+ WHERE table_schema = 'public'
402
+ AND table_type = 'BASE TABLE'
403
+ """)
404
+ tables = cursor.fetchall()
405
+ table_list = [table[0] for table in tables]
406
+ return table_list
407
+ except Exception as e:
408
+ logger.exception("Failed to retrieve tables from PostgreSQL database '%s': %s", db_name, e)
409
+ return None
410
+
337
411
 
338
412
  def insert_data(self,db_name:str,table_name:str,data:dict):
339
413
  """
@@ -370,7 +444,7 @@ class DBConnector:
370
444
  logger.debug("Data inserted into MySQL database '%s', table '%s'", db_name, table_name)
371
445
  except Exception as e:
372
446
  logger.exception("Failed to insert data into MySQL database '%s', table '%s': %s", db_name, table_name, e)
373
- if database_type == "mssql":
447
+ elif database_type == "mssql":
374
448
  try:
375
449
  cursor = database_connection.cursor()
376
450
  columns_sql = ", ".join(f"[{c}]" for c in data.keys())
@@ -391,6 +465,27 @@ class DBConnector:
391
465
  except Exception as e:
392
466
  logger.exception("Insert failed for %s database '%s', table '%s'", database_type, db_name, table_name)
393
467
 
468
+ elif database_type == "postgresql":
469
+ try:
470
+ cursor = database_connection.cursor()
471
+ columns_sql = ", ".join(f'"{c}"' for c in data.keys())
472
+ placeholders = ", ".join("%s" for _ in data)
473
+ values = tuple(data.values())
474
+
475
+ sql = f'INSERT INTO "{table_name}" ({columns_sql}) VALUES ({placeholders})'
476
+
477
+ cursor.execute(sql, values)
478
+ database_connection.commit()
479
+
480
+ logger.info(
481
+ "Data inserted into PostgreSQL database '%s', table '%s'",
482
+ db_name,
483
+ table_name
484
+ )
485
+ cursor.close()
486
+ except Exception as e:
487
+ logger.exception("Insert failed for PostgreSQL database '%s', table '%s'", db_name, table_name)
488
+
394
489
  def get_data(self, db_name: str, table_name: str, num_rows: int = 5):
395
490
  """
396
491
  Retrieve a limited number of rows from a table for display.
@@ -421,6 +516,9 @@ class DBConnector:
421
516
  elif db_type == "mssql":
422
517
  sql = f"SELECT TOP ({num_rows}) * FROM [{table_name}]"
423
518
  cursor.execute(sql)
519
+ elif db_type == "postgresql":
520
+ sql = f'SELECT * FROM "{table_name}" LIMIT %s'
521
+ cursor.execute(sql, (num_rows,))
424
522
  else:
425
523
  return None
426
524
 
@@ -474,7 +572,7 @@ class DBConnector:
474
572
  """
475
573
  cursor.execute(sql, (table_name,))
476
574
  result = cursor.fetchall()
477
- if db_type == "mssql":
575
+ elif db_type == "mssql":
478
576
  sql = """
479
577
  SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE
480
578
  FROM INFORMATION_SCHEMA.COLUMNS
@@ -483,6 +581,16 @@ class DBConnector:
483
581
  """
484
582
  cursor.execute(sql, (table_name,))
485
583
  result = cursor.fetchall()
584
+ elif db_type == "postgresql":
585
+ sql = """
586
+ SELECT column_name, data_type, is_nullable
587
+ FROM information_schema.columns
588
+ WHERE table_schema = 'public'
589
+ AND table_name = %s
590
+ ORDER BY ordinal_position
591
+ """
592
+ cursor.execute(sql, (table_name,))
593
+ result = cursor.fetchall()
486
594
  except Exception:
487
595
  logger.exception(
488
596
  "Failed to retrieve schema from %s database '%s', table '%s'",
agenthink/data_source.py CHANGED
@@ -1,24 +1,38 @@
1
- # ...existing code...
2
- import json
3
- from fastapi import FastAPI
4
- from pydantic import BaseModel
5
- import mysql.connector
6
- from fastapi import APIRouter
7
- import mysql.connector
8
- from azure.identity import ClientSecretCredential
9
- from azure.keyvault.secrets import SecretClient
10
- from mysql.connector import pooling
11
- import json
12
- from azure.storage.blob import BlobServiceClient
13
- from azure.storage.blob import BlobPrefix
14
- import pyodbc
15
- import agenthink.utils as utils
16
- import os
17
- import json
18
- import dotenv
19
- import logging
20
- import re
21
- dotenv.load_dotenv()
1
+ import uuid
2
+ from agenthink.models import ConnectionRequest
22
3
 
4
+ def build_d365_read_call(
5
+ data: ConnectionRequest,
6
+ primary_key: str = "Entry_No",
7
+ filter_query: str | None = None
8
+ ) -> dict:
9
+ """
10
+ Builds a d365_execute tool-call response from ConnectionRequest
11
+ """
23
12
 
13
+ if not data.d365request or not isinstance(data.d365request, list):
14
+ raise ValueError("d365request must be a non-empty list")
24
15
 
16
+ target_url = data.d365request[0].get("url")
17
+ if not target_url:
18
+ raise ValueError("Missing url in d365request")
19
+
20
+ return {
21
+ "status": "tool_calls_pending",
22
+ "session_id": data.session_id,
23
+ "tools_used": ["d365_execute"],
24
+ "tool_call_plan": [
25
+ {
26
+ "tool_call_id": f"call_{uuid.uuid4().hex}",
27
+ "params": {
28
+ "name": "d365_execute",
29
+ "arguments": {
30
+ "operation": "read",
31
+ "target_url": target_url,
32
+ "primary_key": primary_key,
33
+ "filter_query": filter_query,
34
+ }
35
+ }
36
+ }
37
+ ]
38
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenthink
3
- Version: 0.1.22
3
+ Version: 0.1.25
4
4
  Summary: A unified agent framework for connecting workflows, databases, and agents
5
5
  Author: Ritobroto
6
6
  Requires-Python: >=3.10
@@ -0,0 +1,9 @@
1
+ agenthink/__init__.py,sha256=6oUldrZgE76j8OhwsQgVY5vdaPTDFyChOljske-so8U,78
2
+ agenthink/connection.py,sha256=sh4sbc7y-BVyCTMMjTSMMEJYeedB6_XBOKpdBb2jKEY,25477
3
+ agenthink/data_source.py,sha256=hSlpKcS_I6ws9vSKeMnt7EwSHcfO-fFKF8jfXNUE7DI,1196
4
+ agenthink/models.py,sha256=7jm3FPQS50h0t-oCi2SjYW_SmU0nH0d7Hxvqgh15DAw,991
5
+ agenthink/utils.py,sha256=r5o74RbenFhQ7E3N7naoLJ-fYEe9otz0nkcvwKHDTaU,911
6
+ agenthink-0.1.25.dist-info/METADATA,sha256=S9uDnN2gs-F8YlCBkRk2ivQjHezPYnpnm9P0JYEkMFY,1722
7
+ agenthink-0.1.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ agenthink-0.1.25.dist-info/top_level.txt,sha256=rYw4Lx2uqOzbGCSoJEaikme7vS9NvgbVMc26QUIZoZM,10
9
+ agenthink-0.1.25.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- agenthink/__init__.py,sha256=6oUldrZgE76j8OhwsQgVY5vdaPTDFyChOljske-so8U,78
2
- agenthink/connection.py,sha256=5EIZkthtAf_bCICCcEHaLRxP_tEflpJNA1hPHMGDf44,20895
3
- agenthink/data_source.py,sha256=HDi-UDAphTCKiFqWEB_-MfHwXpJKqfn_i05-LdID3M0,561
4
- agenthink/models.py,sha256=7jm3FPQS50h0t-oCi2SjYW_SmU0nH0d7Hxvqgh15DAw,991
5
- agenthink/utils.py,sha256=r5o74RbenFhQ7E3N7naoLJ-fYEe9otz0nkcvwKHDTaU,911
6
- agenthink-0.1.22.dist-info/METADATA,sha256=UO5ZXtCerCMP9Yccti9Exn_TIsNzKWrVecZCybySRtw,1722
7
- agenthink-0.1.22.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- agenthink-0.1.22.dist-info/top_level.txt,sha256=rYw4Lx2uqOzbGCSoJEaikme7vS9NvgbVMc26QUIZoZM,10
9
- agenthink-0.1.22.dist-info/RECORD,,