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.
- qalita/_frontend/.next/BUILD_ID +1 -1
- qalita/_frontend/.next/build-manifest.json +7 -7
- qalita/_frontend/.next/prerender-manifest.json +3 -3
- qalita/_frontend/.next/required-server-files.json +196 -40
- qalita/_frontend/.next/server/app/_global-error/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/_global-error.html +2 -2
- qalita/_frontend/.next/server/app/_global-error.rsc +7 -7
- qalita/_frontend/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- qalita/_frontend/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- qalita/_frontend/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- qalita/_frontend/.next/server/app/_not-found/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/_not-found.html +1 -1
- qalita/_frontend/.next/server/app/_not-found.rsc +9 -9
- qalita/_frontend/.next/server/app/_not-found.segments/_full.segment.rsc +9 -9
- qalita/_frontend/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- qalita/_frontend/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- qalita/_frontend/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- qalita/_frontend/.next/server/app/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/sources/add/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/sources/add/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/sources/add.html +1 -1
- qalita/_frontend/.next/server/app/sources/add.rsc +11 -11
- qalita/_frontend/.next/server/app/sources/add.segments/_full.segment.rsc +11 -11
- qalita/_frontend/.next/server/app/sources/add.segments/_head.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/sources/add.segments/_index.segment.rsc +5 -5
- qalita/_frontend/.next/server/app/sources/add.segments/_tree.segment.rsc +2 -2
- qalita/_frontend/.next/server/app/sources/add.segments/sources/add/__PAGE__.segment.rsc +4 -4
- qalita/_frontend/.next/server/app/sources/add.segments/sources/add.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/sources/add.segments/sources.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/sources/edit/[id]/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/sources/edit/[id]/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/sources/page/build-manifest.json +5 -5
- qalita/_frontend/.next/server/app/sources/page_client-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/app/sources.html +1 -1
- qalita/_frontend/.next/server/app/sources.rsc +11 -11
- qalita/_frontend/.next/server/app/sources.segments/_full.segment.rsc +11 -11
- qalita/_frontend/.next/server/app/sources.segments/_head.segment.rsc +3 -3
- qalita/_frontend/.next/server/app/sources.segments/_index.segment.rsc +5 -5
- qalita/_frontend/.next/server/app/sources.segments/_tree.segment.rsc +2 -2
- qalita/_frontend/.next/server/app/sources.segments/sources/__PAGE__.segment.rsc +4 -4
- qalita/_frontend/.next/server/app/sources.segments/sources.segment.rsc +3 -3
- qalita/_frontend/.next/server/chunks/[root-of-the-server]__bf0c3d33._.js +3 -3
- qalita/_frontend/.next/server/chunks/[root-of-the-server]__f408c708._.js +2 -2
- qalita/_frontend/.next/server/chunks/ssr/[root-of-the-server]__be91267c._.js +1 -1
- qalita/_frontend/.next/server/chunks/ssr/_404f6e81._.js +2 -2
- qalita/_frontend/.next/server/chunks/ssr/_6a67f6f0._.js +2 -2
- qalita/_frontend/.next/server/chunks/ssr/_cb7b44d6._.js +1 -1
- qalita/_frontend/.next/server/chunks/ssr/_d44c43ed._.js +1 -1
- qalita/_frontend/.next/server/chunks/ssr/components_DashboardContent_tsx_c3635665._.js +1 -1
- qalita/_frontend/.next/server/chunks/ssr/node_modules_next_dist_4b9a0874._.js +1 -1
- qalita/_frontend/.next/server/middleware-build-manifest.js +5 -5
- qalita/_frontend/.next/server/pages/404.html +1 -1
- qalita/_frontend/.next/server/pages/500.html +2 -2
- qalita/_frontend/.next/server/server-reference-manifest.js +1 -1
- qalita/_frontend/.next/server/server-reference-manifest.json +1 -1
- qalita/_frontend/.next/static/chunks/0c7542414b6a6f86.js +2 -0
- qalita/_frontend/.next/static/chunks/{89ba62a8ba9b79ce.js → 12daa96885968840.js} +1 -1
- qalita/_frontend/.next/static/chunks/1e6a98e93c470083.css +1 -0
- qalita/_frontend/.next/static/chunks/499b7099996cc9f9.js +1 -0
- qalita/_frontend/.next/static/chunks/694836347d1e5ef3.js +1 -0
- qalita/_frontend/.next/static/chunks/7ea91ca84dc4b3a4.js +1 -0
- qalita/_frontend/.next/static/chunks/89c689b5748e28ed.js +1 -0
- qalita/_frontend/.next/static/chunks/9e71bf77f23416e6.js +1 -0
- qalita/_frontend/.next/static/chunks/aa2a44cc19d89bdb.js +1 -0
- qalita/_frontend/.next/static/chunks/ba22289f779d638e.js +1 -0
- qalita/_frontend/.next/static/chunks/bb05964d928aa166.js +3 -0
- qalita/_frontend/.next/static/chunks/dde1c328f398837e.js +1 -0
- qalita/_frontend/.next/static/chunks/ecbb64dc112ad516.js +1 -0
- qalita/_frontend/.next/static/chunks/facd124df217e016.js +1 -0
- qalita/_frontend/.next/static/chunks/turbopack-9fc8bcb3a9806c66.js +4 -0
- qalita/_frontend/node_modules/@next/env/package.json +1 -1
- qalita/_frontend/node_modules/next/dist/build/index.js +10 -4
- qalita/_frontend/node_modules/next/dist/build/swc/index.js +1 -1
- qalita/_frontend/node_modules/next/dist/build/webpack-config.js +3 -3
- qalita/_frontend/node_modules/next/dist/client/components/segment-cache/lru.js +2 -0
- qalita/_frontend/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +1 -1
- qalita/_frontend/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +1 -1
- qalita/_frontend/node_modules/next/dist/server/config-shared.js +4 -0
- qalita/_frontend/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +1 -1
- qalita/_frontend/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- qalita/_frontend/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- qalita/_frontend/node_modules/next/dist/server/lib/start-server.js +1 -1
- qalita/_frontend/node_modules/next/dist/server/web/adapter.js +1 -1
- qalita/_frontend/node_modules/next/dist/shared/lib/errors/canary-only-config-error.js +1 -1
- qalita/_frontend/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- qalita/_frontend/node_modules/next/dist/telemetry/events/version.js +2 -2
- qalita/_frontend/node_modules/next/package.json +15 -15
- qalita/_frontend/package.json +4 -4
- qalita/_frontend/server.js +1 -1
- qalita/commands/source.py +166 -2
- qalita/commands/worker.py +3 -3
- qalita/commands/worker_grpc.py +113 -3
- qalita/grpc/client.py +260 -34
- qalita/grpc/protos/qalita.proto +26 -0
- qalita/grpc/protos/qalita_pb2.py +80 -76
- qalita/grpc/protos/qalita_pb2_grpc.py +1 -1
- qalita/internal/action_executor.py +1009 -0
- qalita/internal/utils.py +1 -1
- {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/METADATA +4 -3
- {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/RECORD +113 -111
- qalita/_frontend/.next/static/chunks/02a64570f0a14789.js +0 -1
- qalita/_frontend/.next/static/chunks/0b082245f106d665.js +0 -1
- qalita/_frontend/.next/static/chunks/27b3ba70c7ef50a8.js +0 -1
- qalita/_frontend/.next/static/chunks/517e9b74d1a3c0ce.js +0 -1
- qalita/_frontend/.next/static/chunks/58689c96b0676c41.js +0 -1
- qalita/_frontend/.next/static/chunks/6c99da4248e4fcfc.js +0 -1
- qalita/_frontend/.next/static/chunks/acc5da18ff20daa1.js +0 -3
- qalita/_frontend/.next/static/chunks/bdc8a8e7721f5675.js +0 -2
- qalita/_frontend/.next/static/chunks/e0df86cbf44bbf9f.js +0 -1
- qalita/_frontend/.next/static/chunks/e4c3a252774ab7fd.css +0 -1
- qalita/_frontend/.next/static/chunks/e6ce59ba40b863f2.js +0 -1
- qalita/_frontend/.next/static/chunks/ec4b1f1e3cd3ae43.js +0 -1
- qalita/_frontend/.next/static/chunks/turbopack-d21156d03715fafa.js +0 -4
- /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_buildManifest.js +0 -0
- /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_clientMiddlewareManifest.json +0 -0
- /qalita/_frontend/.next/static/{M1H4Lcjc6A78n9p1qVA6d → NJRrkC0Gn13ofbqb0Lb0C}/_ssgManifest.js +0 -0
- {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/WHEEL +0 -0
- {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/entry_points.txt +0 -0
- {qalita-2.9.1.dist-info → qalita-2.10.0.dist-info}/licenses/LICENSE +0 -0
qalita/_frontend/package.json
CHANGED
|
@@ -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.
|
|
20
|
-
"next": "16.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.
|
|
32
|
-
"@types/react": "^19.2.
|
|
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",
|
qalita/_frontend/server.js
CHANGED
|
@@ -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","
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
qalita/commands/worker_grpc.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|