You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

101 lines
3.9 KiB

11 months ago
  1. module.exports.SqlAgentQuery = {
  2. name: "sql-query",
  3. plugin: function () {
  4. const {
  5. getDBClient,
  6. listSQLConnections,
  7. } = require("./SQLConnectors/index.js");
  8. return {
  9. name: "sql-query",
  10. setup(aibitat) {
  11. aibitat.function({
  12. super: aibitat,
  13. name: this.name,
  14. description:
  15. "Run a read-only SQL query on a `database_id` which will return up rows of data related to the query. The query must only be SELECT statements which do not modify the table data. There should be a reasonable LIMIT on the return quantity to prevent long-running or queries which crash the db.",
  16. examples: [
  17. {
  18. prompt: "How many customers are in dvd-rentals?",
  19. call: JSON.stringify({
  20. database_id: "dvd-rentals",
  21. sql_query: "SELECT * FROM customers",
  22. }),
  23. },
  24. {
  25. prompt: "Can you tell me the total volume of sales last month?",
  26. call: JSON.stringify({
  27. database_id: "sales-db",
  28. sql_query:
  29. "SELECT SUM(sale_amount) AS total_sales FROM sales WHERE sale_date >= DATEADD(month, -1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)) AND sale_date < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1)",
  30. }),
  31. },
  32. {
  33. prompt:
  34. "Do we have anyone in the staff table for our production db named 'sam'? ",
  35. call: JSON.stringify({
  36. database_id: "production",
  37. sql_query:
  38. "SElECT * FROM staff WHERE first_name='sam%' OR last_name='sam%'",
  39. }),
  40. },
  41. ],
  42. parameters: {
  43. $schema: "http://json-schema.org/draft-07/schema#",
  44. type: "object",
  45. properties: {
  46. database_id: {
  47. type: "string",
  48. description:
  49. "The database identifier for which we will connect to to query the table schema. This is required to run the SQL query.",
  50. },
  51. sql_query: {
  52. type: "string",
  53. description:
  54. "The raw SQL query to run. Should be a query which does not modify the table and will return results.",
  55. },
  56. },
  57. additionalProperties: false,
  58. },
  59. required: ["database_id", "table_name"],
  60. handler: async function ({ database_id = "", sql_query = "" }) {
  61. this.super.handlerProps.log(`Using the sql-query tool.`);
  62. try {
  63. const databaseConfig = (await listSQLConnections()).find(
  64. (db) => db.database_id === database_id
  65. );
  66. if (!databaseConfig) {
  67. this.super.handlerProps.log(
  68. `sql-query failed to find config!`,
  69. database_id
  70. );
  71. return `No database connection for ${database_id} was found!`;
  72. }
  73. this.super.introspect(
  74. `${this.caller}: Im going to run a query on the ${database_id} to get an answer.`
  75. );
  76. const db = getDBClient(databaseConfig.engine, databaseConfig);
  77. this.super.introspect(`Running SQL: ${sql_query}`);
  78. const result = await db.runQuery(sql_query);
  79. if (result.error) {
  80. this.super.handlerProps.log(
  81. `sql-query tool reported error`,
  82. result.error
  83. );
  84. this.super.introspect(`Error: ${result.error}`);
  85. return `There was an error running the query: ${result.error}`;
  86. }
  87. return JSON.stringify(result);
  88. } catch (e) {
  89. console.error(e);
  90. return e.message;
  91. }
  92. },
  93. });
  94. },
  95. };
  96. },
  97. };