@byted-las/contextlake-openclaw 1.0.0 → 1.0.3

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 (75) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +5 -5
  3. package/dist/src/client/lancedb.js +13 -4
  4. package/dist/src/commands/cli.d.ts +5 -2
  5. package/dist/src/commands/cli.js +94 -10
  6. package/dist/src/commands/index.d.ts +2 -1
  7. package/dist/src/commands/index.js +31 -35
  8. package/dist/src/commands/slashcmd.d.ts +8 -1
  9. package/dist/src/commands/slashcmd.js +90 -6
  10. package/dist/src/commands/tools.d.ts +10 -218
  11. package/dist/src/commands/tools.js +109 -104
  12. package/dist/src/lib/actions/ingest-source.d.ts +15 -0
  13. package/dist/src/lib/actions/ingest-source.js +193 -0
  14. package/dist/src/lib/actions/ingest.d.ts +14 -7
  15. package/dist/src/lib/actions/ingest.js +133 -63
  16. package/dist/src/lib/actions/las-api.d.ts +13 -0
  17. package/dist/src/lib/actions/las-api.js +105 -0
  18. package/dist/src/lib/actions/las-tools.d.ts +3 -0
  19. package/dist/src/lib/actions/las-tools.js +194 -0
  20. package/dist/src/lib/actions/las.d.ts +64 -0
  21. package/dist/src/lib/actions/las.js +72 -0
  22. package/dist/src/lib/actions/manage.d.ts +3 -2
  23. package/dist/src/{skills/las-data-profiler/index.d.ts → lib/actions/profiler.d.ts} +4 -2
  24. package/dist/src/{skills/las-data-profiler/index.js → lib/actions/profiler.js} +19 -3
  25. package/dist/src/lib/actions/retrieve.d.ts +2 -1
  26. package/dist/src/lib/actions/retrieve.js +2 -18
  27. package/{src/skills/las-data-profiler → dist/src/lib/scripts}/s3_catalog.py +10 -1
  28. package/dist/src/processor/loader.js +9 -2
  29. package/dist/src/service/embedding/factory.js +1 -10
  30. package/dist/src/service/embedding/interface.d.ts +8 -1
  31. package/dist/src/service/embedding/local.js +16 -13
  32. package/dist/src/service/embedding/remote.d.ts +7 -0
  33. package/dist/src/service/embedding/remote.js +108 -7
  34. package/dist/src/service/metadata/interface.d.ts +1 -0
  35. package/dist/src/service/metadata/local.d.ts +1 -0
  36. package/dist/src/service/metadata/local.js +6 -0
  37. package/dist/src/skills/SKILL.md +174 -0
  38. package/dist/src/skills/contextlake-delete/SKILL.md +36 -0
  39. package/dist/src/skills/contextlake-ingest/SKILL.md +40 -0
  40. package/dist/src/skills/contextlake-list/SKILL.md +22 -0
  41. package/dist/src/skills/contextlake-retrieve/SKILL.md +37 -0
  42. package/dist/src/skills/las-data-profiler/SKILL.md +174 -0
  43. package/dist/src/utils/config.d.ts +34 -1
  44. package/dist/src/utils/config.js +16 -3
  45. package/dist/src/utils/credentials.d.ts +8 -0
  46. package/dist/src/utils/credentials.js +77 -0
  47. package/index.ts +8 -8
  48. package/openclaw.plugin.json +1 -1
  49. package/package.json +8 -7
  50. package/src/client/lancedb.ts +32 -21
  51. package/src/commands/cli.ts +105 -13
  52. package/src/commands/index.ts +45 -42
  53. package/src/commands/slashcmd.ts +69 -10
  54. package/src/commands/tools.ts +142 -117
  55. package/src/lib/actions/ingest.ts +151 -75
  56. package/src/lib/actions/las-api.ts +119 -0
  57. package/src/lib/actions/las-tools.ts +196 -0
  58. package/src/lib/actions/manage.ts +6 -5
  59. package/src/{skills/las-data-profiler/index.ts → lib/actions/profiler.ts} +21 -4
  60. package/src/lib/actions/retrieve.ts +16 -34
  61. package/src/lib/scripts/s3_catalog.py +617 -0
  62. package/src/processor/loader.ts +12 -4
  63. package/src/service/embedding/factory.ts +1 -8
  64. package/src/service/embedding/interface.ts +9 -1
  65. package/src/service/embedding/remote.ts +133 -13
  66. package/src/service/metadata/interface.ts +1 -0
  67. package/src/service/metadata/local.ts +7 -0
  68. package/src/service/storage/factory.ts +2 -2
  69. package/src/utils/config.ts +61 -8
  70. package/src/utils/credentials.ts +50 -0
  71. package/bin/contextlake-openclaw.js +0 -5
  72. package/dist/src/skills/las-data-profiler/register.d.ts +0 -1
  73. package/dist/src/skills/las-data-profiler/register.js +0 -19
  74. package/src/service/embedding/local.ts +0 -118
  75. package/src/skills/las-data-profiler/register.ts +0 -19
@@ -1,10 +1,13 @@
1
- // @ts-ignore
2
- import { PluginContext } from 'openclaw/plugin-sdk';
3
- import { ingestAssets } from '../lib/actions/ingest';
1
+ import { ingestSource } from '../lib/actions/ingest';
4
2
  import { retrieveAssets } from '../lib/actions/retrieve';
5
3
  import { listAssets, deleteAssets } from '../lib/actions/manage';
4
+ import { connectDataSource, listDataSources, ConnectParams } from '../lib/actions/profiler';
5
+ import { ContextLakeConfig } from '../utils/config';
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+ import * as os from 'os';
6
9
 
7
- export function getSlashCommands(pluginConfig: any, logger: any) {
10
+ export function getSlashCommands(pluginConfig: ContextLakeConfig, logger: any) {
8
11
  return {
9
12
  ingestHandler: async (commandCtx: any) => {
10
13
  const rawArgs = commandCtx.args || "";
@@ -13,12 +16,20 @@ export function getSlashCommands(pluginConfig: any, logger: any) {
13
16
  logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ingest started`, { args });
14
17
  try {
15
18
  if (args.length === 0) {
16
- return { text: `**Error:** Missing files. Usage: /contextlake-ingest /path/to/file1 /path/to/file2` };
19
+ return { text: `**Error:** Missing datasource_name. Usage: /contextlake-ingest <datasource_name>` };
17
20
  }
18
- const result = await ingestAssets({
19
- files: args,
20
- metadata: {}
21
- }, pluginConfig, logger);
21
+
22
+ const datasource_name = args[0];
23
+
24
+ const BASE_DIR = path.join(os.homedir(), '.openclaw', 'contextlake', 'profiler');
25
+ const dsDir = path.join(BASE_DIR, datasource_name);
26
+ const dbPath = path.join(dsDir, 'catalog_db');
27
+
28
+ if (!fs.existsSync(dbPath)) {
29
+ return { text: `**Error:** Data source "${datasource_name}" has not been profiled yet.\n\nPlease run the profiler first using:\n\`/contextlake-profiler <datasource_name> <vendor> <bucket> <prefix> [endpoint] [ak] [sk] [region]\`` };
30
+ }
31
+
32
+ const result = await ingestSource({ datasource_name }, pluginConfig, logger);
22
33
 
23
34
  logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ingest completed`, { resultCount: result.length });
24
35
  return { text: `**Ingest Results (${result.length} files processed):**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
@@ -90,6 +101,54 @@ export function getSlashCommands(pluginConfig: any, logger: any) {
90
101
  logger.error(`[ContextLake] Slash delete failed`, { error: e.message });
91
102
  return { text: `**Error executing delete:** ${e.message}` };
92
103
  }
93
- }
104
+ },
105
+ profilerHandler: async (commandCtx: any) => {
106
+ const rawArgs = commandCtx.args || "";
107
+ const args = rawArgs.split(' ').filter((arg: string) => arg.trim() !== '');
108
+
109
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command profiler started`, { args });
110
+ try {
111
+ if (args.length < 4) {
112
+ return { text: `**Error:** Missing arguments. Usage: /contextlake-profiler <datasource_name> <vendor> <bucket> <prefix> [endpoint] [ak] [sk] [region]` };
113
+ }
114
+
115
+ const [datasource_name, vendor, bucket, prefix, endpoint, access_key, secret_key, region] = args;
116
+
117
+ if (!['volcengine', 'alibaba', 'tencent', 'aws', 'local'].includes(vendor)) {
118
+ return { text: `**Error:** Invalid vendor. Must be one of: volcengine, alibaba, tencent, aws, local` };
119
+ }
120
+
121
+ const params: ConnectParams = {
122
+ datasource_name,
123
+ vendor: vendor as ConnectParams['vendor'],
124
+ bucket,
125
+ prefix,
126
+ endpoint,
127
+ access_key,
128
+ secret_key,
129
+ region,
130
+ };
131
+
132
+ const result = await connectDataSource(params);
133
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command profiler completed`, { result });
134
+ return { text: `**Profiler Results:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
135
+ } catch (e: any) {
136
+ logger.error(`[ContextLake] Slash profiler failed`, { error: e.message });
137
+ return { text: `**Error executing profiler:** ${e.message}` };
138
+ }
139
+ },
140
+
141
+ listDatasourceHandler: async (commandCtx: any) => {
142
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command list-datasource started`);
143
+ try {
144
+ const result = await listDataSources();
145
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command list-datasource completed`, { result });
146
+ return { text: `**Data Sources:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
147
+ } catch (e: any) {
148
+ logger.error(`[ContextLake] Slash list-datasource failed`, { error: e.message });
149
+ return { text: `**Error executing list-datasource:** ${e.message}` };
150
+ }
151
+ },
152
+
94
153
  };
95
154
  }
@@ -1,72 +1,68 @@
1
- import { ingestAssets } from '../lib/actions/ingest';
1
+ import { ingestSource } from '../lib/actions/ingest';
2
2
  import { retrieveAssets } from '../lib/actions/retrieve';
3
3
  import { listAssets, deleteAssets } from '../lib/actions/manage';
4
+ import { connectDataSource, listDataSources } from '../lib/actions/profiler';
5
+ import { getLasTools } from '../lib/actions/las-tools';
6
+ import { ContextLakeConfig } from '../utils/config';
7
+ // @ts-ignore
8
+ import type { AnyAgentTool } from 'openclaw/plugin-sdk';
9
+
10
+ export function getAgentTools(pluginConfig: ContextLakeConfig, logger: any): {
11
+ ingestTool: AnyAgentTool;
12
+ retrieveTool: AnyAgentTool;
13
+ listTool: AnyAgentTool;
14
+ deleteTool: AnyAgentTool;
15
+ lasDataProfilerTool: AnyAgentTool;
16
+ listDatasourceTool: AnyAgentTool;
17
+ lasTools: AnyAgentTool[];
18
+ } {
19
+ const lasTools = getLasTools(pluginConfig, logger);
4
20
 
5
- export function getAgentTools(pluginConfig: any, logger: any) {
6
21
  return {
22
+ lasTools,
23
+ listDatasourceTool: {
24
+ name: 'contextlake-list-datasource',
25
+ label: 'ContextLake List Datasources',
26
+ description: `List all connected and profiled data sources.`,
27
+ parameters: {
28
+ type: 'object',
29
+ properties: {},
30
+ required: [],
31
+ additionalProperties: false
32
+ },
33
+ async execute(toolCallId: string, params: any) {
34
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list-datasource skill, toolCallId: ${toolCallId}`);
35
+ try {
36
+ const result = await listDataSources();
37
+ return {
38
+ content: [{ type: "text", text: JSON.stringify(result) }],
39
+ details: result
40
+ } as any;
41
+ } catch (error: any) {
42
+ logger.error(`[${new Date().toISOString()}] [ContextLake] list-datasource skill failed`, { error: error.message });
43
+ return {
44
+ content: [{ type: "text", text: String(error.message) }],
45
+ details: { error: error.message }
46
+ } as any;
47
+ }
48
+ }
49
+ },
7
50
  ingestTool: {
8
51
  name: 'contextlake-ingest',
9
52
  label: 'ContextLake Ingest',
10
- description: `Upload, ingest, and index documents into the ContextLake Knowledge Base (知识库) / Knowledge Lake (知识湖).
53
+ description: `Process and ingest all files from a connected data source into the knowledge base.
11
54
  Use this tool when the user wants to "将知识注入", "上传文件", "入库", "添加文档", "ingest files", or "add knowledge".
12
- Supports processing of various file types including PDF, Word, Markdown, and Text.
13
- Automatically handles text extraction, cleaning, chunking, embedding generation, and storage.
14
-
15
- Example User Queries:
16
- - "帮我把这个文档注入到知识湖中"
17
- - "上传这份 PDF 到知识库"
18
- - "Please ingest these documents into ContextLake"
19
- - "将 /path/to/doc.txt 添加到知识库"`,
55
+ Supports multimodal files (text, images, audio, video, pdf) by using LAS models to understand and embed them.
56
+ Must be called after a data source has been successfully profiled via \`las-data-profiler\`.`,
20
57
  parameters: {
21
58
  type: 'object',
22
59
  properties: {
23
- files: {
24
- type: 'array',
25
- items: { type: 'string' },
26
- description: 'List of file paths to ingest'
27
- },
28
- metadata: {
29
- type: 'object',
30
- description: 'Optional JSON metadata to attach to documents',
31
- additionalProperties: true
32
- },
33
- chunkSize: {
34
- type: 'integer',
35
- description: 'Chunk size for text splitting'
36
- },
37
- overlap: {
38
- type: 'integer',
39
- description: 'Overlap size for text splitting'
40
- }
41
- },
42
- required: ['files'],
43
- additionalProperties: false
44
- },
45
- schema: {
46
- type: 'object',
47
- properties: {
48
- files: {
49
- type: 'array',
50
- items: { type: 'string' },
51
- description: 'List of file paths to ingest'
52
- },
53
- metadata: {
54
- type: 'object',
55
- description: 'Optional JSON metadata to attach to documents',
56
- additionalProperties: true
57
- },
58
- chunkSize: {
59
- type: 'integer',
60
- description: 'Chunk size for text splitting'
61
- },
62
- overlap: {
63
- type: 'integer',
64
- description: 'Overlap size for text splitting'
65
- }
60
+ datasource_name: { type: 'string', description: 'Name of the data source previously profiled' }
66
61
  },
67
- required: ['files'],
62
+ required: ['datasource_name'],
68
63
  additionalProperties: false
69
64
  },
65
+
70
66
  async execute(toolCallId: string, params: any) {
71
67
  logger.info(`[${new Date().toISOString()}] [ContextLake] Executing ingest skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
72
68
 
@@ -78,35 +74,35 @@ Example User Queries:
78
74
  } catch (e) {
79
75
  logger.warn(`[ContextLake] Received string params, possibly toolCallId?`, { params });
80
76
  return {
81
- success: false,
82
- error: `Invalid params format: received string "${params}", expected object with 'files' array.`
83
- };
77
+ content: [{ type: "text", text: `Invalid params format: received string "${params}", expected object with 'datasource_name'.` }],
78
+ details: { error: `Invalid params format: received string "${params}", expected object with 'datasource_name'.` }
79
+ } as any;
84
80
  }
85
81
  }
86
82
 
87
- if (!actualParams.files && actualParams.params && actualParams.params.files) {
83
+ if (!actualParams.datasource_name && actualParams.params && actualParams.params.datasource_name) {
88
84
  actualParams = actualParams.params;
89
85
  }
90
86
 
91
- if (!actualParams.files || !Array.isArray(actualParams.files)) {
87
+ if (!actualParams.datasource_name) {
92
88
  return {
93
- success: false,
94
- error: `Invalid params: 'files' must be an array. Received keys: ${Object.keys(actualParams)}`
95
- };
89
+ content: [{ type: "text", text: `Invalid params: 'datasource_name' is required. Received keys: ${Object.keys(actualParams)}` }],
90
+ details: { error: `Invalid params: 'datasource_name' is required. Received keys: ${Object.keys(actualParams)}` }
91
+ } as any;
96
92
  }
97
93
 
98
- const result = await ingestAssets(actualParams, pluginConfig, logger);
94
+ const result = await ingestSource(actualParams, pluginConfig, logger);
99
95
  logger.info(`[${new Date().toISOString()}] [ContextLake] Ingest skill completed successfully`, { resultSummary: Array.isArray(result) ? `Processed ${result.length} items` : 'Success' });
100
96
  return {
101
- success: true,
102
- result
103
- };
97
+ content: [{ type: "text", text: JSON.stringify(result) }],
98
+ details: result
99
+ } as any;
104
100
  } catch (error: any) {
105
101
  logger.error(`[${new Date().toISOString()}] [ContextLake] Ingest skill failed`, { error: error.message, stack: error.stack });
106
102
  return {
107
- success: false,
108
- error: error.message
109
- };
103
+ content: [{ type: "text", text: String(error.message) }],
104
+ details: { error: error.message }
105
+ } as any;
110
106
  }
111
107
  }
112
108
  },
@@ -133,17 +129,7 @@ Example User Queries:
133
129
  required: ['query'],
134
130
  additionalProperties: false
135
131
  },
136
- schema: {
137
- type: 'object',
138
- properties: {
139
- query: { type: 'string', description: 'Search query' },
140
- top_k: { type: 'integer', description: 'Number of results to return' },
141
- filter: { type: 'string', description: 'Filter string' },
142
- include_binary: { type: 'boolean', description: 'Whether to include binary content' }
143
- },
144
- required: ['query'],
145
- additionalProperties: false
146
- },
132
+
147
133
  async execute(toolCallId: string, params: any) {
148
134
  logger.info(`[${new Date().toISOString()}] [ContextLake] Executing retrieve skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
149
135
 
@@ -163,23 +149,25 @@ Example User Queries:
163
149
 
164
150
  if (!actualParams || typeof actualParams.query !== 'string') {
165
151
  return {
166
- success: false,
167
- error: `Invalid params: 'query' is required and must be a string. Received: ${JSON.stringify(actualParams)}`
168
- };
152
+ content: [{ type: "text", text: `Invalid params: 'query' is required and must be a string. Received: ${JSON.stringify(actualParams)}` }],
153
+ details: { error: `Invalid params: 'query' is required and must be a string. Received: ${JSON.stringify(actualParams)}` }
154
+ } as any;
169
155
  }
170
156
 
171
157
  const result = await retrieveAssets(actualParams, pluginConfig, logger);
172
158
  logger.info(`[${new Date().toISOString()}] [ContextLake] Retrieve skill completed`, { resultCount: Array.isArray(result) ? result.length : 0 });
173
159
  return {
174
- success: true,
175
- result
176
- };
160
+ content: [{ type: "text", text: JSON.stringify(result) }],
161
+ details: result
162
+ } as any;
177
163
  } catch (error: any) {
178
164
  logger.error(`[${new Date().toISOString()}] [ContextLake] Retrieve skill failed`, { error: error.message, stack: error.stack });
179
165
  return {
180
- success: false,
181
- error: error.message
182
- };
166
+ content: [{ type: "text", text: String(error.message
167
+ ) }],
168
+ details: { error: error.message
169
+ }
170
+ } as any;
183
171
  }
184
172
  }
185
173
  },
@@ -201,13 +189,7 @@ Example User Queries:
201
189
  required: [],
202
190
  additionalProperties: false
203
191
  },
204
- schema: {
205
- type: 'object',
206
- properties: {
207
- limit: { type: 'integer', description: 'Limit for list action' }
208
- },
209
- required: []
210
- },
192
+
211
193
  async execute(toolCallId: string, params: any) {
212
194
  logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
213
195
 
@@ -219,15 +201,17 @@ Example User Queries:
219
201
  const result = await listAssets(actualParams, pluginConfig, logger);
220
202
  logger.info(`[${new Date().toISOString()}] [ContextLake] List skill completed`, { count: Array.isArray(result) ? result.length : 0 });
221
203
  return {
222
- success: true,
223
- result
224
- };
204
+ content: [{ type: "text", text: JSON.stringify(result) }],
205
+ details: result
206
+ } as any;
225
207
  } catch (error: any) {
226
208
  logger.error(`[${new Date().toISOString()}] [ContextLake] List skill failed`, { error: error.message, stack: error.stack });
227
209
  return {
228
- success: false,
229
- error: error.message
230
- };
210
+ content: [{ type: "text", text: String(error.message
211
+ ) }],
212
+ details: { error: error.message
213
+ }
214
+ } as any;
231
215
  }
232
216
  }
233
217
  },
@@ -251,14 +235,7 @@ Example User Queries:
251
235
  required: [],
252
236
  additionalProperties: false
253
237
  },
254
- schema: {
255
- type: 'object',
256
- properties: {
257
- file_ids: { type: 'array', items: { type: 'string' }, description: 'File IDs to delete' },
258
- filter: { type: 'string', description: 'Filter string for deletion' }
259
- },
260
- required: []
261
- },
238
+
262
239
  async execute(toolCallId: string, params: any) {
263
240
  logger.info(`[${new Date().toISOString()}] [ContextLake] Executing delete skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
264
241
 
@@ -270,15 +247,63 @@ Example User Queries:
270
247
  const result = await deleteAssets(actualParams, pluginConfig, logger);
271
248
  logger.info(`[${new Date().toISOString()}] [ContextLake] Delete skill completed`, { result });
272
249
  return {
273
- success: true,
274
- result
275
- };
250
+ content: [{ type: "text", text: JSON.stringify(result) }],
251
+ details: result
252
+ } as any;
276
253
  } catch (error: any) {
277
254
  logger.error(`[${new Date().toISOString()}] [ContextLake] Delete skill failed`, { error: error.message, stack: error.stack });
278
255
  return {
279
- success: false,
280
- error: error.message
281
- };
256
+ content: [{ type: "text", text: String(error.message
257
+ ) }],
258
+ details: { error: error.message
259
+ }
260
+ } as any;
261
+ }
262
+ }
263
+ },
264
+ lasDataProfilerTool: {
265
+ name: 'las-data-profiler',
266
+ label: 'LAS Data Profiler',
267
+ description: 'Connect to a data source (TOS/OSS/COS/S3/Local) and profile its structure, schemas, and media metadata into LanceDB',
268
+ parameters: {
269
+ type: 'object',
270
+ properties: {
271
+ datasource_name: { type: 'string', description: 'Name of the data source' },
272
+ vendor: { type: 'string', enum: ['volcengine', 'alibaba', 'tencent', 'aws', 'local'], description: 'Data source type' },
273
+ endpoint: { type: 'string', description: 'S3 Endpoint URL (not needed for local)' },
274
+ access_key: { type: 'string', description: 'Credential ID for the data source' },
275
+ secret_key: { type: 'string', description: 'Credential value for the data source' },
276
+ region: { type: 'string', description: 'Region identifier (e.g. cn-beijing)' },
277
+ bucket: { type: 'string', description: 'Bucket name (or local root directory for local vendor)' },
278
+ prefix: { type: 'string', description: 'Path prefix to limit scan scope' },
279
+ sample_rows: { type: 'integer', description: 'Number of rows to sample per structured file' }
280
+ },
281
+ required: ['datasource_name', 'vendor', 'bucket', 'prefix'],
282
+ additionalProperties: false
283
+ },
284
+
285
+ async execute(toolCallId: string, params: any) {
286
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las-data-profiler skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
287
+
288
+ try {
289
+ let actualParams = params;
290
+ if (params && params.params) {
291
+ actualParams = params.params;
292
+ }
293
+ const result = await connectDataSource(actualParams);
294
+ logger.info(`[${new Date().toISOString()}] [ContextLake] las-data-profiler skill completed`, { result });
295
+ return {
296
+ content: [{ type: "text", text: JSON.stringify(result) }],
297
+ details: result
298
+ } as any;
299
+ } catch (error: any) {
300
+ logger.error(`[${new Date().toISOString()}] [ContextLake] las-data-profiler skill failed`, { error: error.message, stack: error.stack });
301
+ return {
302
+ content: [{ type: "text", text: String(error.message
303
+ ) }],
304
+ details: { error: error.message
305
+ }
306
+ } as any;
282
307
  }
283
308
  }
284
309
  }