qalita 2.9.1__py3-none-any.whl → 2.10.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 (126) hide show
  1. qalita/_frontend/.next/BUILD_ID +1 -1
  2. qalita/_frontend/.next/build-manifest.json +7 -7
  3. qalita/_frontend/.next/prerender-manifest.json +3 -3
  4. qalita/_frontend/.next/required-server-files.json +196 -40
  5. qalita/_frontend/.next/server/app/_global-error/page/build-manifest.json +5 -5
  6. qalita/_frontend/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. qalita/_frontend/.next/server/app/_global-error.html +2 -2
  8. qalita/_frontend/.next/server/app/_global-error.rsc +7 -7
  9. qalita/_frontend/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  10. qalita/_frontend/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  11. qalita/_frontend/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  12. qalita/_frontend/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  13. qalita/_frontend/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. qalita/_frontend/.next/server/app/_not-found/page/build-manifest.json +5 -5
  15. qalita/_frontend/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. qalita/_frontend/.next/server/app/_not-found.html +1 -1
  17. qalita/_frontend/.next/server/app/_not-found.rsc +9 -9
  18. qalita/_frontend/.next/server/app/_not-found.segments/_full.segment.rsc +9 -9
  19. qalita/_frontend/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
  20. qalita/_frontend/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
  21. qalita/_frontend/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. qalita/_frontend/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. qalita/_frontend/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. qalita/_frontend/.next/server/app/page/build-manifest.json +5 -5
  25. qalita/_frontend/.next/server/app/page_client-reference-manifest.js +1 -1
  26. qalita/_frontend/.next/server/app/sources/add/page/build-manifest.json +5 -5
  27. qalita/_frontend/.next/server/app/sources/add/page_client-reference-manifest.js +1 -1
  28. qalita/_frontend/.next/server/app/sources/add.html +1 -1
  29. qalita/_frontend/.next/server/app/sources/add.rsc +11 -11
  30. qalita/_frontend/.next/server/app/sources/add.segments/_full.segment.rsc +11 -11
  31. qalita/_frontend/.next/server/app/sources/add.segments/_head.segment.rsc +3 -3
  32. qalita/_frontend/.next/server/app/sources/add.segments/_index.segment.rsc +5 -5
  33. qalita/_frontend/.next/server/app/sources/add.segments/_tree.segment.rsc +2 -2
  34. qalita/_frontend/.next/server/app/sources/add.segments/sources/add/__PAGE__.segment.rsc +4 -4
  35. qalita/_frontend/.next/server/app/sources/add.segments/sources/add.segment.rsc +3 -3
  36. qalita/_frontend/.next/server/app/sources/add.segments/sources.segment.rsc +3 -3
  37. qalita/_frontend/.next/server/app/sources/edit/[id]/page/build-manifest.json +5 -5
  38. qalita/_frontend/.next/server/app/sources/edit/[id]/page_client-reference-manifest.js +1 -1
  39. qalita/_frontend/.next/server/app/sources/page/build-manifest.json +5 -5
  40. qalita/_frontend/.next/server/app/sources/page_client-reference-manifest.js +1 -1
  41. qalita/_frontend/.next/server/app/sources.html +1 -1
  42. qalita/_frontend/.next/server/app/sources.rsc +11 -11
  43. qalita/_frontend/.next/server/app/sources.segments/_full.segment.rsc +11 -11
  44. qalita/_frontend/.next/server/app/sources.segments/_head.segment.rsc +3 -3
  45. qalita/_frontend/.next/server/app/sources.segments/_index.segment.rsc +5 -5
  46. qalita/_frontend/.next/server/app/sources.segments/_tree.segment.rsc +2 -2
  47. qalita/_frontend/.next/server/app/sources.segments/sources/__PAGE__.segment.rsc +4 -4
  48. qalita/_frontend/.next/server/app/sources.segments/sources.segment.rsc +3 -3
  49. qalita/_frontend/.next/server/chunks/[root-of-the-server]__bf0c3d33._.js +3 -3
  50. qalita/_frontend/.next/server/chunks/[root-of-the-server]__f408c708._.js +2 -2
  51. qalita/_frontend/.next/server/chunks/ssr/[root-of-the-server]__be91267c._.js +1 -1
  52. qalita/_frontend/.next/server/chunks/ssr/_404f6e81._.js +2 -2
  53. qalita/_frontend/.next/server/chunks/ssr/_6a67f6f0._.js +2 -2
  54. qalita/_frontend/.next/server/chunks/ssr/_cb7b44d6._.js +1 -1
  55. qalita/_frontend/.next/server/chunks/ssr/_d44c43ed._.js +1 -1
  56. qalita/_frontend/.next/server/chunks/ssr/components_DashboardContent_tsx_c3635665._.js +1 -1
  57. qalita/_frontend/.next/server/chunks/ssr/node_modules_next_dist_4b9a0874._.js +1 -1
  58. qalita/_frontend/.next/server/middleware-build-manifest.js +5 -5
  59. qalita/_frontend/.next/server/pages/404.html +1 -1
  60. qalita/_frontend/.next/server/pages/500.html +2 -2
  61. qalita/_frontend/.next/server/server-reference-manifest.js +1 -1
  62. qalita/_frontend/.next/server/server-reference-manifest.json +1 -1
  63. qalita/_frontend/.next/static/chunks/0c7542414b6a6f86.js +2 -0
  64. qalita/_frontend/.next/static/chunks/{89ba62a8ba9b79ce.js → 12daa96885968840.js} +1 -1
  65. qalita/_frontend/.next/static/chunks/1e6a98e93c470083.css +1 -0
  66. qalita/_frontend/.next/static/chunks/499b7099996cc9f9.js +1 -0
  67. qalita/_frontend/.next/static/chunks/694836347d1e5ef3.js +1 -0
  68. qalita/_frontend/.next/static/chunks/7ea91ca84dc4b3a4.js +1 -0
  69. qalita/_frontend/.next/static/chunks/89c689b5748e28ed.js +1 -0
  70. qalita/_frontend/.next/static/chunks/9e71bf77f23416e6.js +1 -0
  71. qalita/_frontend/.next/static/chunks/aa2a44cc19d89bdb.js +1 -0
  72. qalita/_frontend/.next/static/chunks/ba22289f779d638e.js +1 -0
  73. qalita/_frontend/.next/static/chunks/bb05964d928aa166.js +3 -0
  74. qalita/_frontend/.next/static/chunks/dde1c328f398837e.js +1 -0
  75. qalita/_frontend/.next/static/chunks/ecbb64dc112ad516.js +1 -0
  76. qalita/_frontend/.next/static/chunks/facd124df217e016.js +1 -0
  77. qalita/_frontend/.next/static/chunks/turbopack-9fc8bcb3a9806c66.js +4 -0
  78. qalita/_frontend/node_modules/@next/env/package.json +1 -1
  79. qalita/_frontend/node_modules/next/dist/build/index.js +10 -4
  80. qalita/_frontend/node_modules/next/dist/build/swc/index.js +1 -1
  81. qalita/_frontend/node_modules/next/dist/build/webpack-config.js +3 -3
  82. qalita/_frontend/node_modules/next/dist/client/components/segment-cache/lru.js +2 -0
  83. qalita/_frontend/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +1 -1
  84. qalita/_frontend/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +1 -1
  85. qalita/_frontend/node_modules/next/dist/server/config-shared.js +4 -0
  86. qalita/_frontend/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +1 -1
  87. qalita/_frontend/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
  88. qalita/_frontend/node_modules/next/dist/server/lib/app-info-log.js +1 -1
  89. qalita/_frontend/node_modules/next/dist/server/lib/start-server.js +1 -1
  90. qalita/_frontend/node_modules/next/dist/server/web/adapter.js +1 -1
  91. qalita/_frontend/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  92. qalita/_frontend/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
  93. qalita/_frontend/node_modules/next/dist/telemetry/events/version.js +2 -2
  94. qalita/_frontend/node_modules/next/package.json +15 -15
  95. qalita/_frontend/package.json +4 -4
  96. qalita/_frontend/server.js +1 -1
  97. qalita/commands/source.py +166 -2
  98. qalita/commands/worker.py +3 -3
  99. qalita/commands/worker_grpc.py +113 -3
  100. qalita/grpc/client.py +260 -34
  101. qalita/grpc/protos/qalita.proto +26 -0
  102. qalita/grpc/protos/qalita_pb2.py +80 -76
  103. qalita/grpc/protos/qalita_pb2_grpc.py +1 -1
  104. qalita/internal/action_executor.py +1009 -0
  105. qalita/internal/utils.py +1 -1
  106. {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/METADATA +4 -3
  107. {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/RECORD +113 -111
  108. qalita/_frontend/.next/static/chunks/02a64570f0a14789.js +0 -1
  109. qalita/_frontend/.next/static/chunks/0b082245f106d665.js +0 -1
  110. qalita/_frontend/.next/static/chunks/27b3ba70c7ef50a8.js +0 -1
  111. qalita/_frontend/.next/static/chunks/517e9b74d1a3c0ce.js +0 -1
  112. qalita/_frontend/.next/static/chunks/58689c96b0676c41.js +0 -1
  113. qalita/_frontend/.next/static/chunks/6c99da4248e4fcfc.js +0 -1
  114. qalita/_frontend/.next/static/chunks/acc5da18ff20daa1.js +0 -3
  115. qalita/_frontend/.next/static/chunks/bdc8a8e7721f5675.js +0 -2
  116. qalita/_frontend/.next/static/chunks/e0df86cbf44bbf9f.js +0 -1
  117. qalita/_frontend/.next/static/chunks/e4c3a252774ab7fd.css +0 -1
  118. qalita/_frontend/.next/static/chunks/e6ce59ba40b863f2.js +0 -1
  119. qalita/_frontend/.next/static/chunks/ec4b1f1e3cd3ae43.js +0 -1
  120. qalita/_frontend/.next/static/chunks/turbopack-d21156d03715fafa.js +0 -4
  121. /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_buildManifest.js +0 -0
  122. /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_clientMiddlewareManifest.json +0 -0
  123. /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_ssgManifest.js +0 -0
  124. {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/WHEEL +0 -0
  125. {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/entry_points.txt +0 -0
  126. {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/licenses/LICENSE +0 -0
@@ -16,8 +16,8 @@
16
16
  "@tailwindcss/forms": "^0.5.10",
17
17
  "class-variance-authority": "^0.7.1",
18
18
  "clsx": "^2.1.1",
19
- "lucide-react": "^0.469.0",
20
- "next": "16.1.1",
19
+ "lucide-react": "^0.563.0",
20
+ "next": "16.1.4",
21
21
  "next-themes": "^0.4.6",
22
22
  "react": "^19.2.3",
23
23
  "react-dom": "^19.2.3",
@@ -28,8 +28,8 @@
28
28
  "tailwindcss-animate": "^1.0.7"
29
29
  },
30
30
  "devDependencies": {
31
- "@types/node": "^25.0.3",
32
- "@types/react": "^19.2.7",
31
+ "@types/node": "^25.0.10",
32
+ "@types/react": "^19.2.9",
33
33
  "@types/react-dom": "^19.2.3",
34
34
  "autoprefixer": "^10.4.23",
35
35
  "postcss": "^8.5.6",
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
9
9
  const hostname = process.env.HOSTNAME || '0.0.0.0'
10
10
 
11
11
  let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
12
- const nextConfig = {"distDir":"./.next","cacheComponents":false,"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","assetPrefix":"","output":"standalone","trailingSlash":false,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":false},"reactMaxHeadersLength":6000,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"basePath":"","expireTime":31536000,"generateEtags":true,"poweredByHeader":true,"cacheHandlers":{},"cacheMaxMemorySize":52428800,"compress":true,"i18n":null,"httpAgentOptions":{"keepAlive":true},"pageExtensions":["tsx","ts","jsx","js"],"useFileSystemPublicRoutes":true,"experimental":{"ppr":false,"staleTimes":{"dynamic":0,"static":300},"dynamicOnHover":false,"inlineCss":false,"authInterrupts":false,"fetchCacheKeyPrefix":"","isrFlushToDisk":true,"optimizeCss":false,"nextScriptWorkers":false,"disableOptimizedLoading":false,"largePageDataBytes":128000,"serverComponentsHmrCache":true,"caseSensitiveRoutes":false,"validateRSCRequestHeaders":false,"useSkewCookie":false,"preloadEntriesOnStart":true,"hideLogsAfterAbort":false,"removeUncaughtErrorAndRejectionListeners":false,"imgOptConcurrency":null,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"imgOptTimeoutInSeconds":7,"proxyClientMaxBodySize":10485760,"trustHostHeader":false,"isExperimentalCompile":false}}
12
+ const nextConfig = {"env":{},"webpack":null,"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.js","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":true,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/qalita-cli/qalita-cli/frontend","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"dynamicOnHover":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":1,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":false,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":false,"lockDistDir":true,"isolatedDevBuild":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":false,"optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.js","turbopack":{"root":"/home/runner/work/qalita-cli/qalita-cli/frontend"},"distDirRoot":".next"}
13
13
 
14
14
  process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
15
15
 
qalita/commands/source.py CHANGED
@@ -130,7 +130,9 @@ def validate_source(config):
130
130
  if type_for_test == "database":
131
131
  type_for_test = source["config"].get("type", "database")
132
132
  if type_for_test in [
133
- "mysql", "postgresql", "sqlite", "mongodb", "oracle", "s3", "gcs", "azure_blob", "hdfs", "file", "folder"
133
+ "mysql", "postgresql", "sqlite", "mongodb", "oracle", "s3", "gcs", "azure_blob", "hdfs", "file", "folder",
134
+ "snowflake", "bigquery", "databricks", "redshift", "clickhouse", "duckdb", "trino",
135
+ "teradata", "sap_hana", "cassandra", "elasticsearch", "ibm_db2", "athena", "synapse"
134
136
  ]:
135
137
  if not test_connection(source["config"], type_for_test):
136
138
  logger.error(f"Connection test failed for source [{source['name']}] of type {type_for_test}")
@@ -244,6 +246,20 @@ def validate_source_object(config, source: dict, skip_connection: bool = False,
244
246
  "hdfs",
245
247
  "file",
246
248
  "folder",
249
+ "snowflake",
250
+ "bigquery",
251
+ "databricks",
252
+ "redshift",
253
+ "clickhouse",
254
+ "duckdb",
255
+ "trino",
256
+ "teradata",
257
+ "sap_hana",
258
+ "cassandra",
259
+ "elasticsearch",
260
+ "ibm_db2",
261
+ "athena",
262
+ "synapse",
247
263
  ]
248
264
  if type_for_test in supported:
249
265
  if not test_connection(conf, type_for_test):
@@ -656,7 +672,7 @@ def add(config):
656
672
 
657
673
  # ask for the source type
658
674
  source["type"] = click.prompt(
659
- "Source type (file, folder, postgresql, mysql, oracle, mssql, sqlite, mongodb, s3, gcs, azure_blob, hdfs)",
675
+ "Source type (file, folder, postgresql, mysql, oracle, mssql, sqlite, mongodb, s3, gcs, azure_blob, hdfs, snowflake, bigquery, databricks, redshift, clickhouse, duckdb, trino, teradata, sap_hana, cassandra, elasticsearch, ibm_db2, athena, synapse)",
660
676
  )
661
677
 
662
678
  # Configure according to the selected source type
@@ -739,6 +755,154 @@ def add(config):
739
755
  source["config"]["port"] = click.prompt("HDFS port")
740
756
  source["config"]["user"] = click.prompt("HDFS user")
741
757
  source["config"]["path"] = click.prompt("HDFS path")
758
+ elif source["type"] == "snowflake":
759
+ source["config"]["account"] = click.prompt("Snowflake account identifier (e.g., xy12345.us-east-1)")
760
+ source["config"]["user"] = click.prompt("Snowflake username")
761
+ source["config"]["password"] = click.prompt("Snowflake password", hide_input=True)
762
+ source["config"]["warehouse"] = click.prompt("Snowflake warehouse")
763
+ source["config"]["database"] = click.prompt("Snowflake database")
764
+ source["config"]["schema"] = click.prompt("Snowflake schema", default="PUBLIC")
765
+ source["config"]["role"] = click.prompt("Snowflake role (optional)", default="")
766
+ source["config"]["table_or_query"] = click.prompt(
767
+ "Table name, list of table names or SQL query (default '*' scans the entire database)",
768
+ default="*",
769
+ )
770
+ elif source["type"] == "bigquery":
771
+ source["config"]["project"] = click.prompt("Google Cloud project ID")
772
+ source["config"]["dataset"] = click.prompt("BigQuery dataset name")
773
+ source["config"]["credentials_json"] = click.prompt("Path to service account JSON credentials file")
774
+ source["config"]["table_or_query"] = click.prompt(
775
+ "Table name, list of table names or SQL query (default '*' scans the entire dataset)",
776
+ default="*",
777
+ )
778
+ elif source["type"] == "databricks":
779
+ source["config"]["server_hostname"] = click.prompt("Databricks server hostname (e.g., adb-xxx.azuredatabricks.net)")
780
+ source["config"]["http_path"] = click.prompt("Databricks HTTP path (e.g., /sql/1.0/warehouses/xxx)")
781
+ source["config"]["access_token"] = click.prompt("Databricks access token", hide_input=True)
782
+ source["config"]["catalog"] = click.prompt("Databricks catalog (optional)", default="")
783
+ source["config"]["schema"] = click.prompt("Databricks schema (optional)", default="")
784
+ source["config"]["table_or_query"] = click.prompt(
785
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
786
+ default="*",
787
+ )
788
+ elif source["type"] == "redshift":
789
+ source["config"]["host"] = click.prompt("Redshift cluster endpoint")
790
+ source["config"]["port"] = click.prompt("Redshift port", default="5439")
791
+ source["config"]["user"] = click.prompt("Redshift username")
792
+ source["config"]["password"] = click.prompt("Redshift password", hide_input=True)
793
+ source["config"]["database"] = click.prompt("Redshift database")
794
+ source["config"]["schema"] = click.prompt("Redshift schema", default="public")
795
+ source["config"]["table_or_query"] = click.prompt(
796
+ "Table name, list of table names or SQL query (default '*' scans the entire schema)",
797
+ default="*",
798
+ )
799
+ elif source["type"] == "clickhouse":
800
+ source["config"]["host"] = click.prompt("ClickHouse host")
801
+ source["config"]["port"] = click.prompt("ClickHouse port", default="8123")
802
+ source["config"]["user"] = click.prompt("ClickHouse username", default="default")
803
+ source["config"]["password"] = click.prompt("ClickHouse password (optional)", default="", hide_input=True)
804
+ source["config"]["database"] = click.prompt("ClickHouse database", default="default")
805
+ source["config"]["protocol"] = click.prompt("ClickHouse protocol (http or native)", default="http")
806
+ source["config"]["table_or_query"] = click.prompt(
807
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
808
+ default="*",
809
+ )
810
+ elif source["type"] == "duckdb":
811
+ source["config"]["path"] = click.prompt("DuckDB file path (or :memory: for in-memory)", default=":memory:")
812
+ motherduck = click.prompt("Use MotherDuck cloud?", type=bool, default=False)
813
+ if motherduck:
814
+ source["config"]["motherduck_token"] = click.prompt("MotherDuck token", hide_input=True)
815
+ source["config"]["schema"] = click.prompt("DuckDB schema", default="main")
816
+ source["config"]["table_or_query"] = click.prompt(
817
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
818
+ default="*",
819
+ )
820
+ elif source["type"] == "trino":
821
+ source["config"]["host"] = click.prompt("Trino host")
822
+ source["config"]["port"] = click.prompt("Trino port", default="8080")
823
+ source["config"]["user"] = click.prompt("Trino username", default="trino")
824
+ source["config"]["catalog"] = click.prompt("Trino catalog")
825
+ source["config"]["schema"] = click.prompt("Trino schema")
826
+ source["config"]["http_scheme"] = click.prompt("HTTP scheme (http or https)", default="https")
827
+ source["config"]["table_or_query"] = click.prompt(
828
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
829
+ default="*",
830
+ )
831
+ elif source["type"] == "teradata":
832
+ source["config"]["host"] = click.prompt("Teradata host")
833
+ source["config"]["user"] = click.prompt("Teradata username")
834
+ source["config"]["password"] = click.prompt("Teradata password", hide_input=True)
835
+ source["config"]["database"] = click.prompt("Teradata database (optional)", default="")
836
+ source["config"]["schema"] = click.prompt("Teradata schema (optional)", default="")
837
+ source["config"]["table_or_query"] = click.prompt(
838
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
839
+ default="*",
840
+ )
841
+ elif source["type"] == "sap_hana":
842
+ source["config"]["host"] = click.prompt("SAP HANA host")
843
+ source["config"]["port"] = click.prompt("SAP HANA port", default="30015")
844
+ source["config"]["user"] = click.prompt("SAP HANA username")
845
+ source["config"]["password"] = click.prompt("SAP HANA password", hide_input=True)
846
+ source["config"]["schema"] = click.prompt("SAP HANA schema (optional)", default="")
847
+ source["config"]["table_or_query"] = click.prompt(
848
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
849
+ default="*",
850
+ )
851
+ elif source["type"] == "cassandra":
852
+ source["config"]["host"] = click.prompt("Cassandra host")
853
+ source["config"]["port"] = click.prompt("Cassandra port", default="9042")
854
+ source["config"]["username"] = click.prompt("Cassandra username (optional)", default="")
855
+ source["config"]["password"] = click.prompt("Cassandra password (optional)", default="", hide_input=True)
856
+ source["config"]["keyspace"] = click.prompt("Cassandra keyspace")
857
+ source["config"]["table_or_query"] = click.prompt(
858
+ "Table name, list of table names or CQL query (default '*' scans all tables)",
859
+ default="*",
860
+ )
861
+ elif source["type"] == "elasticsearch":
862
+ source["config"]["host"] = click.prompt("Elasticsearch host")
863
+ source["config"]["port"] = click.prompt("Elasticsearch port", default="9200")
864
+ source["config"]["username"] = click.prompt("Elasticsearch username (optional)", default="")
865
+ source["config"]["password"] = click.prompt("Elasticsearch password (optional)", default="", hide_input=True)
866
+ source["config"]["use_ssl"] = click.prompt("Use SSL?", type=bool, default=False)
867
+ source["config"]["cloud_id"] = click.prompt("Elastic Cloud ID (optional, leave empty for self-hosted)", default="")
868
+ source["config"]["api_key"] = click.prompt("API Key (optional)", default="", hide_input=True)
869
+ source["config"]["table_or_query"] = click.prompt(
870
+ "Index name or pattern (default '*' scans all indices)",
871
+ default="*",
872
+ )
873
+ elif source["type"] == "ibm_db2":
874
+ source["config"]["host"] = click.prompt("IBM DB2 host")
875
+ source["config"]["port"] = click.prompt("IBM DB2 port", default="50000")
876
+ source["config"]["user"] = click.prompt("IBM DB2 username")
877
+ source["config"]["password"] = click.prompt("IBM DB2 password", hide_input=True)
878
+ source["config"]["database"] = click.prompt("IBM DB2 database")
879
+ source["config"]["schema"] = click.prompt("IBM DB2 schema (optional)", default="")
880
+ source["config"]["table_or_query"] = click.prompt(
881
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
882
+ default="*",
883
+ )
884
+ elif source["type"] == "athena":
885
+ source["config"]["region"] = click.prompt("AWS region", default="us-east-1")
886
+ source["config"]["s3_staging_dir"] = click.prompt("S3 staging directory (e.g., s3://bucket/path/)")
887
+ source["config"]["database"] = click.prompt("Athena database")
888
+ source["config"]["workgroup"] = click.prompt("Athena workgroup (optional)", default="")
889
+ source["config"]["access_key"] = click.prompt("AWS Access Key (optional, uses IAM if empty)", default="")
890
+ source["config"]["secret_key"] = click.prompt("AWS Secret Key (optional)", default="", hide_input=True)
891
+ source["config"]["table_or_query"] = click.prompt(
892
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
893
+ default="*",
894
+ )
895
+ elif source["type"] == "synapse":
896
+ source["config"]["host"] = click.prompt("Azure Synapse host (e.g., xxx.sql.azuresynapse.net)")
897
+ source["config"]["port"] = click.prompt("Azure Synapse port", default="1433")
898
+ source["config"]["user"] = click.prompt("Azure Synapse username")
899
+ source["config"]["password"] = click.prompt("Azure Synapse password", hide_input=True)
900
+ source["config"]["database"] = click.prompt("Azure Synapse database")
901
+ source["config"]["schema"] = click.prompt("Azure Synapse schema", default="dbo")
902
+ source["config"]["table_or_query"] = click.prompt(
903
+ "Table name, list of table names or SQL query (default '*' scans all tables)",
904
+ default="*",
905
+ )
742
906
  else:
743
907
  # Generic fallback
744
908
  click.echo(f"Unknown or unsupported source type: {source['type']}")
qalita/commands/worker.py CHANGED
@@ -673,7 +673,7 @@ def job_run(
673
673
 
674
674
  """Runs a job"""
675
675
  agent_conf = config.load_worker_config()
676
- send_alive(config_file=agent_conf, mode="job", status="starting")
676
+ # Note: Worker status stays "online" during job execution (only job status changes)
677
677
 
678
678
  # Get Source Version & Version ID
679
679
  # if source_version_id is None:
@@ -868,7 +868,7 @@ def job_run(
868
868
  sys.exit(1)
869
869
 
870
870
  # run the job
871
- send_alive(config_file=agent_conf, mode="job", status="busy")
871
+ # Note: Worker status stays "online" during job execution (only job status changes)
872
872
  try:
873
873
  if job["id"] is not None:
874
874
  r = send_api_request(
@@ -937,7 +937,7 @@ def job_run(
937
937
  else:
938
938
  status = "failed"
939
939
 
940
- send_alive(config_file=agent_conf, mode="job", status=status)
940
+ # Note: Worker status stays "online" (only job status reflects success/failure)
941
941
  r = send_api_request(
942
942
  request=f"/api/v2/jobs/{job['id']}",
943
943
  mode="put",
@@ -21,6 +21,7 @@ import croniter
21
21
  from qalita.internal.utils import logger, get_version, validate_token
22
22
  from qalita.internal.request import send_request
23
23
  from qalita.internal.data_preview import preview_source, DataPreviewResult
24
+ from qalita.internal.action_executor import get_action_executor, ActionResult
24
25
  from qalita.grpc import GrpcClient
25
26
  from qalita.grpc.protos import qalita_pb2
26
27
  from qalita.commands.pack import run_pack
@@ -194,6 +195,7 @@ class GrpcWorkerRunner:
194
195
  self.grpc_client.on_routine_received(self._handle_routine_trigger)
195
196
  self.grpc_client.on_data_preview_request(self._handle_data_preview_request)
196
197
  self.grpc_client.on_add_source_request(self._handle_add_source_request)
198
+ self.grpc_client.on_agent_action_request(self._handle_agent_action_request)
197
199
  self.grpc_client.on_disconnect(self._handle_disconnect)
198
200
 
199
201
  try:
@@ -620,6 +622,114 @@ class GrpcWorkerRunner:
620
622
  connectivity_verified=False,
621
623
  )
622
624
 
625
+ async def _handle_agent_action_request(self, request: qalita_pb2.AgentActionRequest) -> None:
626
+ """
627
+ Handle an agent action request from the platform.
628
+
629
+ This is called when the Studio LLM agent requests to execute an action
630
+ on a data source (e.g., SQL query, read data, describe schema).
631
+ The worker:
632
+ 1. Finds the source configuration locally
633
+ 2. Executes the action using the ActionExecutor
634
+ 3. Sends back an AgentActionResponse via gRPC stream
635
+ """
636
+ request_id = request.request_id
637
+ action_type = request.action_type
638
+ source_id = request.source_id
639
+ params_json = request.parameters_json
640
+ timeout = request.timeout_seconds if request.HasField('timeout_seconds') else None
641
+
642
+ logger.info(f"Processing agent action request {request_id}: {action_type} on source {source_id}")
643
+
644
+ try:
645
+ # Parse parameters
646
+ params = json.loads(params_json) if params_json else {}
647
+
648
+ # Find the source in local configuration
649
+ source_conf = self.config.load_source_config(verbose=False)
650
+ matching_sources = [
651
+ s for s in source_conf.get("sources", [])
652
+ if str(s.get("id")) == str(source_id)
653
+ ]
654
+
655
+ if not matching_sources:
656
+ logger.warning(f"Source {source_id} not found in local config")
657
+ await self.grpc_client.send_agent_action_response(
658
+ request_id=request_id,
659
+ ok=False,
660
+ action_type=action_type,
661
+ error=f"Source {source_id} not found in local configuration",
662
+ )
663
+ return
664
+
665
+ source_config = matching_sources[0]
666
+ logger.info(f"Found source config for {source_id}: type={source_config.get('type')}")
667
+
668
+ # Execute the action
669
+ executor = get_action_executor()
670
+ result: ActionResult = executor.execute(
671
+ action_type=action_type,
672
+ source_config=source_config,
673
+ params=params,
674
+ timeout_seconds=timeout,
675
+ )
676
+
677
+ # Convert DataPreviewResult to protobuf if present
678
+ data_proto = None
679
+ if result.data:
680
+ data_proto = qalita_pb2.DataPreviewResponse(
681
+ request_id=request_id,
682
+ ok=result.data.ok,
683
+ data_type=result.data.data_type,
684
+ )
685
+ if result.data.error:
686
+ data_proto.error = result.data.error
687
+ if result.data.headers:
688
+ data_proto.headers.extend(result.data.headers)
689
+ if result.data.rows:
690
+ for row in result.data.rows:
691
+ data_row = qalita_pb2.DataRow(values=row)
692
+ data_proto.rows.append(data_row)
693
+ if result.data.total_rows is not None:
694
+ data_proto.total_rows = result.data.total_rows
695
+ if result.data.content:
696
+ data_proto.content = result.data.content
697
+
698
+ # Send the response
699
+ await self.grpc_client.send_agent_action_response(
700
+ request_id=request_id,
701
+ ok=result.ok,
702
+ action_type=result.action_type,
703
+ error=result.error,
704
+ result_json=result.result_json,
705
+ data=data_proto,
706
+ execution_time_ms=result.execution_time_ms,
707
+ )
708
+
709
+ if result.ok:
710
+ logger.success(f"Agent action '{action_type}' completed for source {source_id} in {result.execution_time_ms}ms")
711
+ else:
712
+ logger.warning(f"Agent action '{action_type}' failed for source {source_id}: {result.error}")
713
+
714
+ except json.JSONDecodeError as e:
715
+ error_msg = f"Invalid parameters JSON: {str(e)}"
716
+ logger.error(f"Error handling agent action request {request_id}: {error_msg}")
717
+ await self.grpc_client.send_agent_action_response(
718
+ request_id=request_id,
719
+ ok=False,
720
+ action_type=action_type,
721
+ error=error_msg,
722
+ )
723
+ except Exception as e:
724
+ error_msg = f"Internal error: {str(e)}"
725
+ logger.error(f"Error handling agent action request {request_id}: {error_msg}")
726
+ await self.grpc_client.send_agent_action_response(
727
+ request_id=request_id,
728
+ ok=False,
729
+ action_type=action_type,
730
+ error=error_msg,
731
+ )
732
+
623
733
  async def _execute_job(
624
734
  self,
625
735
  job_id: int,
@@ -642,7 +752,7 @@ class GrpcWorkerRunner:
642
752
 
643
753
  # Update job status to running
644
754
  await self.grpc_client.send_job_status(job_id, "running", start_date=start_time)
645
- await self.grpc_client.send_worker_status(self.worker_id, "busy")
755
+ # Note: Worker status stays "online" during job execution (only job status changes)
646
756
 
647
757
  try:
648
758
  # Get source info
@@ -779,7 +889,7 @@ class GrpcWorkerRunner:
779
889
  end_date=end_time,
780
890
  logs_id=logs_id,
781
891
  )
782
- await self.grpc_client.send_worker_status(self.worker_id, final_status)
892
+ # Note: Worker status stays "online" (only job status reflects success/failure)
783
893
 
784
894
  elapsed_time = end_time - start_time
785
895
  logger.success(f"Job {job_id} finished with status {final_status}")
@@ -790,7 +900,7 @@ class GrpcWorkerRunner:
790
900
  logger.error(f"Job {job_id} failed: {e}")
791
901
  end_time = datetime.now(timezone.utc)
792
902
  await self.grpc_client.send_job_status(job_id, "failed", error_message=str(e), end_date=end_time)
793
- await self.grpc_client.send_worker_status(self.worker_id, "failed")
903
+ # Note: Worker status stays "online" (only job status reflects failure)
794
904
  raise
795
905
 
796
906
  async def _pull_pack(self, pack_id: int, asset: qalita_pb2.AssetUrl) -> str: