@byted-las/contextlake-openclaw 1.0.9 → 1.0.14

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.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ const commands_1 = require("./src/commands");
4
4
  const plugin = {
5
5
  id: 'contextlake-openclaw',
6
6
  name: 'ContextLake',
7
- version: '1.0.9',
7
+ version: '1.0.12',
8
8
  description: 'A lightweight knowledge base plugin for OpenClaw using LanceDB and TOS, with data profiling support',
9
9
  configSchema: {
10
10
  type: 'object',
@@ -1,5 +1,8 @@
1
1
  import { ContextLakeConfig } from '../utils/config';
2
2
  export declare function getCliCommands(pluginConfig: ContextLakeConfig, logger: any): {
3
+ listS3ObjectsAction: (url: string, options: any) => Promise<void>;
4
+ readS3ObjectAction: (url: string, options: any) => Promise<void>;
5
+ generatePresignedUrlAction: (url: string, options: any) => Promise<void>;
3
6
  searchAction: (query: any, options: any) => Promise<void>;
4
7
  listAction: (options: any) => Promise<void>;
5
8
  deleteAction: (options: any) => Promise<void>;
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCliCommands = getCliCommands;
4
4
  const retrieve_1 = require("../lib/actions/retrieve");
5
5
  const manage_1 = require("../lib/actions/manage");
6
+ const las_tools_1 = require("../lib/actions/las-tools");
7
+ const s3_tools_1 = require("../lib/actions/s3-tools");
6
8
  const credentials_1 = require("../utils/credentials");
7
9
  function parseOptionalInt(value, fallback) {
8
10
  const parsed = Number.parseInt(String(value), 10);
@@ -30,7 +32,93 @@ function parseMetadata(metadata) {
30
32
  }
31
33
  }
32
34
  function getCliCommands(pluginConfig, logger) {
35
+ const lasTools = (0, las_tools_1.getLasTools)(pluginConfig, logger);
36
+ const lasActions = {};
37
+ for (const tool of lasTools) {
38
+ lasActions[`${tool.name}Action`] = async (dataStr) => {
39
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} started`);
40
+ try {
41
+ let data = {};
42
+ try {
43
+ data = JSON.parse(dataStr);
44
+ }
45
+ catch (e) {
46
+ // if it's not valid JSON and the tool accepts a simple string/url, try to handle it.
47
+ // But LAS tools typically require a data object.
48
+ data = { url: dataStr };
49
+ }
50
+ let params = tool.name === 'las_bare_image_text_embedding'
51
+ ? data
52
+ : { data };
53
+ const result = await tool.execute('cli', params);
54
+ // eslint-disable-next-line no-console
55
+ console.log(JSON.stringify(result, null, 2));
56
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} success`);
57
+ }
58
+ catch (e) {
59
+ console.error('Error:', e.message);
60
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} failed`, { error: e.message, stack: e.stack });
61
+ }
62
+ };
63
+ }
33
64
  return {
65
+ ...lasActions,
66
+ listS3ObjectsAction: async (url, options) => {
67
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects started`, { url, options });
68
+ try {
69
+ // Parse prefix from URL if present
70
+ let prefix = '';
71
+ if (url && !url.startsWith('file://')) {
72
+ try {
73
+ const parsedUrl = new URL(url);
74
+ prefix = parsedUrl.pathname.replace(/^\//, '');
75
+ // Reconstruct url without path to pass to listS3Objects as base url
76
+ url = `${parsedUrl.protocol}//${parsedUrl.host}`;
77
+ }
78
+ catch (e) {
79
+ // ignore, leave url as is
80
+ }
81
+ }
82
+ const result = await (0, s3_tools_1.listS3Objects)({ url }, prefix, parseOptionalInt(options.maxKeys, 1000), options.continuationToken);
83
+ // eslint-disable-next-line no-console
84
+ console.log(JSON.stringify(result, null, 2));
85
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects success`);
86
+ }
87
+ catch (e) {
88
+ console.error('Error:', e.message);
89
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects failed`, { error: e.message, stack: e.stack });
90
+ }
91
+ },
92
+ readS3ObjectAction: async (url, options) => {
93
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object started`, { url, options });
94
+ try {
95
+ const parsedUrl = new URL(url);
96
+ const key = parsedUrl.pathname.replace(/^\//, '');
97
+ const result = await (0, s3_tools_1.readS3Object)({ url }, key, options.maxBytes ? parseOptionalInt(options.maxBytes, 0) : undefined);
98
+ // eslint-disable-next-line no-console
99
+ console.log(result.toString('utf-8'));
100
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object success`);
101
+ }
102
+ catch (e) {
103
+ console.error('Error:', e.message);
104
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object failed`, { error: e.message, stack: e.stack });
105
+ }
106
+ },
107
+ generatePresignedUrlAction: async (url, options) => {
108
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url started`, { url, options });
109
+ try {
110
+ const parsedUrl = new URL(url);
111
+ const key = parsedUrl.pathname.replace(/^\//, '');
112
+ const result = await (0, s3_tools_1.getPresignedUrl)({ url }, key, parseOptionalInt(options.expiresIn, 3600));
113
+ // eslint-disable-next-line no-console
114
+ console.log(result);
115
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url success`);
116
+ }
117
+ catch (e) {
118
+ console.error('Error:', e.message);
119
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url failed`, { error: e.message, stack: e.stack });
120
+ }
121
+ },
34
122
  searchAction: async (query, options) => {
35
123
  logger.info(`[${new Date().toISOString()}] [ContextLake] CLI search started`, { query, options });
36
124
  try {
@@ -67,6 +67,29 @@ function registerAll(ctx, logger) {
67
67
  contextlake.command('onboard')
68
68
  .description('Configure credentials for ContextLake')
69
69
  .action(commands.onboardAction);
70
+ // S3 Tools
71
+ contextlake.command('list-s3-objects <url>')
72
+ .description('List objects in an S3-compatible bucket or local directory')
73
+ .option('--max-keys <number>', 'Maximum number of keys to return', '1000')
74
+ .option('--continuation-token <string>', 'Continuation token for pagination')
75
+ .action(commands.listS3ObjectsAction);
76
+ contextlake.command('read-s3-object <url>')
77
+ .description('Read the contents of an S3 object')
78
+ .option('--max-bytes <number>', 'Maximum number of bytes to read')
79
+ .action(commands.readS3ObjectAction);
80
+ contextlake.command('generate-presigned-url <url>')
81
+ .description('Generate a presigned HTTP URL for an S3/TOS object')
82
+ .option('--expires-in <number>', 'Expiration time in seconds', '3600')
83
+ .action(commands.generatePresignedUrlAction);
84
+ // LAS Tools
85
+ const tools = (0, tools_1.getAgentTools)(pluginConfig, logger);
86
+ const lasTools = tools.lasTools;
87
+ for (const tool of lasTools) {
88
+ const cmdName = tool.name.replace(/_/g, '-');
89
+ contextlake.command(`${cmdName} <data>`)
90
+ .description(tool.label)
91
+ .action(commands[`${tool.name}Action`]);
92
+ }
70
93
  }, { commands: ['contextlake'] });
71
94
  logger.info(`[${new Date().toISOString()}] [ContextLake] CLI commands registered`);
72
95
  }
@@ -105,6 +128,34 @@ function registerAll(ctx, logger) {
105
128
  acceptsArgs: false,
106
129
  handler: slashCommands.listDatasourceHandler
107
130
  });
131
+ ctx.registerCommand({
132
+ name: 'contextlake-list-s3-objects',
133
+ description: 'List objects in an S3-compatible bucket or local directory',
134
+ acceptsArgs: true,
135
+ handler: slashCommands.listS3ObjectsHandler
136
+ });
137
+ ctx.registerCommand({
138
+ name: 'contextlake-read-s3-object',
139
+ description: 'Read the contents of an S3 object',
140
+ acceptsArgs: true,
141
+ handler: slashCommands.readS3ObjectHandler
142
+ });
143
+ ctx.registerCommand({
144
+ name: 'contextlake-generate-presigned-url',
145
+ description: 'Generate a presigned HTTP URL for an S3/TOS object',
146
+ acceptsArgs: true,
147
+ handler: slashCommands.generatePresignedUrlHandler
148
+ });
149
+ const tools = (0, tools_1.getAgentTools)(pluginConfig, logger);
150
+ for (const tool of tools.lasTools) {
151
+ const cmdName = tool.name.replace(/_/g, '-');
152
+ ctx.registerCommand({
153
+ name: `contextlake-${cmdName}`,
154
+ description: tool.label,
155
+ acceptsArgs: true,
156
+ handler: slashCommands[`${tool.name}Handler`]
157
+ });
158
+ }
108
159
  logger.info(`[${new Date().toISOString()}] [ContextLake] Slash commands registered`);
109
160
  }
110
161
  catch (error) {
@@ -1,5 +1,14 @@
1
1
  import { ContextLakeConfig } from '../utils/config';
2
2
  export declare function getSlashCommands(pluginConfig: ContextLakeConfig, logger: any): {
3
+ listS3ObjectsHandler: (commandCtx: any) => Promise<{
4
+ text: string;
5
+ }>;
6
+ readS3ObjectHandler: (commandCtx: any) => Promise<{
7
+ text: string;
8
+ }>;
9
+ generatePresignedUrlHandler: (commandCtx: any) => Promise<{
10
+ text: string;
11
+ }>;
3
12
  listHandler: (commandCtx: any) => Promise<{
4
13
  text: string;
5
14
  }>;
@@ -4,8 +4,116 @@ exports.getSlashCommands = getSlashCommands;
4
4
  const retrieve_1 = require("../lib/actions/retrieve");
5
5
  const manage_1 = require("../lib/actions/manage");
6
6
  const profiler_1 = require("../lib/actions/profiler");
7
+ const las_tools_1 = require("../lib/actions/las-tools");
8
+ const s3_tools_1 = require("../lib/actions/s3-tools");
9
+ function parseOptionalInt(value, fallback) {
10
+ const parsed = Number.parseInt(String(value), 10);
11
+ return Number.isFinite(parsed) ? parsed : fallback;
12
+ }
7
13
  function getSlashCommands(pluginConfig, logger) {
14
+ const lasTools = (0, las_tools_1.getLasTools)(pluginConfig, logger);
15
+ const lasHandlers = {};
16
+ for (const tool of lasTools) {
17
+ lasHandlers[`${tool.name}Handler`] = async (commandCtx) => {
18
+ const rawArgs = commandCtx.args || "";
19
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ${tool.name} started`, { args: rawArgs });
20
+ try {
21
+ if (!rawArgs.trim()) {
22
+ return { text: `**Error:** Missing arguments. Please provide JSON data or URL.` };
23
+ }
24
+ let data = {};
25
+ try {
26
+ data = JSON.parse(rawArgs);
27
+ }
28
+ catch (e) {
29
+ data = { url: rawArgs.trim() };
30
+ }
31
+ let params = tool.name === 'las_bare_image_text_embedding'
32
+ ? data
33
+ : { data };
34
+ const result = await tool.execute('slash', params);
35
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ${tool.name} completed`);
36
+ return { text: `**${tool.label} Results:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
37
+ }
38
+ catch (e) {
39
+ logger.error(`[ContextLake] Slash ${tool.name} failed`, { error: e.message });
40
+ return { text: `**Error executing ${tool.label}:** ${e.message}` };
41
+ }
42
+ };
43
+ }
8
44
  return {
45
+ ...lasHandlers,
46
+ listS3ObjectsHandler: async (commandCtx) => {
47
+ const rawArgs = commandCtx.args || "";
48
+ const args = rawArgs.split(' ').filter((arg) => arg.trim() !== '');
49
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command list-s3-objects started`, { args });
50
+ try {
51
+ if (args.length === 0) {
52
+ return { text: `**Error:** Missing URL. Usage: /contextlake-list-s3-objects <url> [maxKeys]` };
53
+ }
54
+ let url = args[0];
55
+ const maxKeys = args.length > 1 ? parseOptionalInt(args[1], 1000) : 1000;
56
+ let prefix = '';
57
+ if (url && !url.startsWith('file://')) {
58
+ try {
59
+ const parsedUrl = new URL(url);
60
+ prefix = parsedUrl.pathname.replace(/^\//, '');
61
+ // Reconstruct url without path to pass to listS3Objects as base url
62
+ url = `${parsedUrl.protocol}//${parsedUrl.host}`;
63
+ }
64
+ catch (e) {
65
+ // ignore, leave url as is
66
+ }
67
+ }
68
+ const result = await (0, s3_tools_1.listS3Objects)({ url }, prefix, maxKeys);
69
+ return { text: `**List S3 Objects Results:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
70
+ }
71
+ catch (e) {
72
+ logger.error(`[ContextLake] Slash list-s3-objects failed`, { error: e.message });
73
+ return { text: `**Error executing list-s3-objects:** ${e.message}` };
74
+ }
75
+ },
76
+ readS3ObjectHandler: async (commandCtx) => {
77
+ const rawArgs = commandCtx.args || "";
78
+ const args = rawArgs.split(' ').filter((arg) => arg.trim() !== '');
79
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command read-s3-object started`, { args });
80
+ try {
81
+ if (args.length === 0) {
82
+ return { text: `**Error:** Missing URL. Usage: /contextlake-read-s3-object <url> [maxBytes]` };
83
+ }
84
+ const url = args[0];
85
+ const parsedUrl = new URL(url);
86
+ const key = parsedUrl.pathname.replace(/^\//, '');
87
+ const maxBytes = args.length > 1 ? parseOptionalInt(args[1], 0) : undefined;
88
+ const result = await (0, s3_tools_1.readS3Object)({ url }, key, maxBytes);
89
+ // Return base64 or string based on content? Returning string for simplicity in slash commands.
90
+ return { text: `**Read S3 Object Results:**\n\`\`\`\n${result.toString('utf-8')}\n\`\`\`` };
91
+ }
92
+ catch (e) {
93
+ logger.error(`[ContextLake] Slash read-s3-object failed`, { error: e.message });
94
+ return { text: `**Error executing read-s3-object:** ${e.message}` };
95
+ }
96
+ },
97
+ generatePresignedUrlHandler: async (commandCtx) => {
98
+ const rawArgs = commandCtx.args || "";
99
+ const args = rawArgs.split(' ').filter((arg) => arg.trim() !== '');
100
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command generate-presigned-url started`, { args });
101
+ try {
102
+ if (args.length === 0) {
103
+ return { text: `**Error:** Missing URL. Usage: /contextlake-generate-presigned-url <url> [expiresIn]` };
104
+ }
105
+ const url = args[0];
106
+ const parsedUrl = new URL(url);
107
+ const key = parsedUrl.pathname.replace(/^\//, '');
108
+ const expiresIn = args.length > 1 ? parseOptionalInt(args[1], 3600) : 3600;
109
+ const result = await (0, s3_tools_1.getPresignedUrl)({ url }, key, expiresIn);
110
+ return { text: `**Presigned URL:**\n${result}` };
111
+ }
112
+ catch (e) {
113
+ logger.error(`[ContextLake] Slash generate-presigned-url failed`, { error: e.message });
114
+ return { text: `**Error executing generate-presigned-url:** ${e.message}` };
115
+ }
116
+ },
9
117
  listHandler: async (commandCtx) => {
10
118
  const rawArgs = commandCtx.args || "";
11
119
  const args = rawArgs.split(' ').filter((arg) => arg.trim() !== '');
package/index.ts CHANGED
@@ -5,7 +5,7 @@ import { registerAll } from './src/commands';
5
5
  const plugin = {
6
6
  id: 'contextlake-openclaw',
7
7
  name: 'ContextLake',
8
- version: '1.0.9',
8
+ version: '1.0.12',
9
9
  description: 'A lightweight knowledge base plugin for OpenClaw using LanceDB and TOS, with data profiling support',
10
10
  configSchema: {
11
11
  type: 'object',
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "contextlake-openclaw",
3
3
  "name": "ContextLake",
4
- "version": "1.0.9",
4
+ "version": "1.0.12",
5
5
  "description": "A lightweight knowledge base plugin for OpenClaw using LanceDB and TOS, with data profiling support",
6
6
  "skills": ["./src/skills"],
7
7
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byted-las/contextlake-openclaw",
3
- "version": "1.0.9",
3
+ "version": "1.0.14",
4
4
  "description": "ContextLake OpenClaw Plugin for managing knowledge base",
5
5
  "main": "index.ts",
6
6
  "files": [
@@ -18,8 +18,6 @@
18
18
  "build": "tsc && npm run copy-assets",
19
19
  "copy-assets": "mkdir -p dist/src/skills && cp -r src/skills/* dist/src/skills/ 2>/dev/null || true && mkdir -p dist/src/lib/scripts && cp src/lib/scripts/*.py dist/src/lib/scripts/ 2>/dev/null || true",
20
20
  "test": "vitest --reporter verbose",
21
- "test:local": "npx ts-node scripts/local-test.ts",
22
- "test:profiler": "npx ts-node scripts/local-profiler-test.ts",
23
21
  "cli": "npx ts-node scripts/cli.ts"
24
22
  },
25
23
  "keywords": [
@@ -3,6 +3,8 @@ import { ingestSource } from '../lib/actions/ingest';
3
3
  import { retrieveAssets } from '../lib/actions/retrieve';
4
4
  import { listAssets, deleteAssets } from '../lib/actions/manage';
5
5
  import { connectDataSource, ConnectParams } from '../lib/actions/profiler';
6
+ import { getLasTools } from '../lib/actions/las-tools';
7
+ import { listS3Objects, readS3Object, getPresignedUrl } from '../lib/actions/s3-tools';
6
8
  import { loadCredentials, saveCredentials, promptForInput } from '../utils/credentials';
7
9
  import { ContextLakeConfig } from '../utils/config';
8
10
 
@@ -36,7 +38,100 @@ function parseMetadata(metadata: any): Record<string, any> {
36
38
  }
37
39
 
38
40
  export function getCliCommands(pluginConfig: ContextLakeConfig, logger: any) {
41
+ const lasTools = getLasTools(pluginConfig, logger);
42
+ const lasActions: Record<string, any> = {};
43
+
44
+ for (const tool of lasTools) {
45
+ lasActions[`${tool.name}Action`] = async (dataStr: string) => {
46
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} started`);
47
+ try {
48
+ let data = {};
49
+ try {
50
+ data = JSON.parse(dataStr);
51
+ } catch (e) {
52
+ // if it's not valid JSON and the tool accepts a simple string/url, try to handle it.
53
+ // But LAS tools typically require a data object.
54
+ data = { url: dataStr };
55
+ }
56
+
57
+ let params = tool.name === 'las_bare_image_text_embedding'
58
+ ? data
59
+ : { data };
60
+
61
+ const result = await tool.execute('cli', params);
62
+ // eslint-disable-next-line no-console
63
+ console.log(JSON.stringify(result, null, 2));
64
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} success`);
65
+ } catch (e: any) {
66
+ console.error('Error:', e.message);
67
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI ${tool.name} failed`, { error: e.message, stack: e.stack });
68
+ }
69
+ };
70
+ }
71
+
39
72
  return {
73
+ ...lasActions,
74
+
75
+ listS3ObjectsAction: async (url: string, options: any) => {
76
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects started`, { url, options });
77
+ try {
78
+ // Parse prefix from URL if present
79
+ let prefix = '';
80
+ if (url && !url.startsWith('file://')) {
81
+ try {
82
+ const parsedUrl = new URL(url);
83
+ prefix = parsedUrl.pathname.replace(/^\//, '');
84
+ // Reconstruct url without path to pass to listS3Objects as base url
85
+ url = `${parsedUrl.protocol}//${parsedUrl.host}`;
86
+ } catch (e) {
87
+ // ignore, leave url as is
88
+ }
89
+ }
90
+
91
+ const result = await listS3Objects(
92
+ { url },
93
+ prefix,
94
+ parseOptionalInt(options.maxKeys, 1000),
95
+ options.continuationToken
96
+ );
97
+ // eslint-disable-next-line no-console
98
+ console.log(JSON.stringify(result, null, 2));
99
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects success`);
100
+ } catch (e: any) {
101
+ console.error('Error:', e.message);
102
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI list-s3-objects failed`, { error: e.message, stack: e.stack });
103
+ }
104
+ },
105
+
106
+ readS3ObjectAction: async (url: string, options: any) => {
107
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object started`, { url, options });
108
+ try {
109
+ const parsedUrl = new URL(url);
110
+ const key = parsedUrl.pathname.replace(/^\//, '');
111
+ const result = await readS3Object({ url }, key, options.maxBytes ? parseOptionalInt(options.maxBytes, 0) : undefined);
112
+ // eslint-disable-next-line no-console
113
+ console.log(result.toString('utf-8'));
114
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object success`);
115
+ } catch (e: any) {
116
+ console.error('Error:', e.message);
117
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI read-s3-object failed`, { error: e.message, stack: e.stack });
118
+ }
119
+ },
120
+
121
+ generatePresignedUrlAction: async (url: string, options: any) => {
122
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url started`, { url, options });
123
+ try {
124
+ const parsedUrl = new URL(url);
125
+ const key = parsedUrl.pathname.replace(/^\//, '');
126
+ const result = await getPresignedUrl({ url }, key, parseOptionalInt(options.expiresIn, 3600));
127
+ // eslint-disable-next-line no-console
128
+ console.log(result);
129
+ logger.info(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url success`);
130
+ } catch (e: any) {
131
+ console.error('Error:', e.message);
132
+ logger.error(`[${new Date().toISOString()}] [ContextLake] CLI generate-presigned-url failed`, { error: e.message, stack: e.stack });
133
+ }
134
+ },
40
135
  searchAction: async (query: any, options: any) => {
41
136
  logger.info(`[${new Date().toISOString()}] [ContextLake] CLI search started`, { query, options });
42
137
  try {
@@ -12,35 +12,35 @@ export function registerAll(ctx: OpenClawPluginApi, logger: PluginLogger) {
12
12
  try {
13
13
  const tools = getAgentTools(pluginConfig, logger);
14
14
 
15
- ctx.registerTool(tools.retrieveTool );
15
+ ctx.registerTool(tools.retrieveTool, { name: tools.retrieveTool.name });
16
16
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.retrieveTool.name}`);
17
17
 
18
- ctx.registerTool(tools.listTool );
18
+ ctx.registerTool(tools.listTool, { name: tools.listTool.name });
19
19
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.listTool.name}`);
20
20
 
21
- ctx.registerTool(tools.deleteTool );
21
+ ctx.registerTool(tools.deleteTool, { name: tools.deleteTool.name });
22
22
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.deleteTool.name}`);
23
23
 
24
- ctx.registerTool(tools.listS3ObjectsTool );
24
+ ctx.registerTool(tools.listS3ObjectsTool, { name: tools.listS3ObjectsTool.name });
25
25
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.listS3ObjectsTool.name}`);
26
26
 
27
- ctx.registerTool(tools.readS3ObjectTool );
27
+ ctx.registerTool(tools.readS3ObjectTool, { name: tools.readS3ObjectTool.name });
28
28
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.readS3ObjectTool.name}`);
29
29
 
30
- ctx.registerTool(tools.writeLanceCatalogTool );
30
+ ctx.registerTool(tools.writeLanceCatalogTool, { name: tools.writeLanceCatalogTool.name });
31
31
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.writeLanceCatalogTool.name}`);
32
32
 
33
- ctx.registerTool(tools.readLanceCatalogTool );
33
+ ctx.registerTool(tools.readLanceCatalogTool, { name: tools.readLanceCatalogTool.name });
34
34
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.readLanceCatalogTool.name}`);
35
35
 
36
- ctx.registerTool(tools.generatePresignedUrlTool );
36
+ ctx.registerTool(tools.generatePresignedUrlTool, { name: tools.generatePresignedUrlTool.name });
37
37
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.generatePresignedUrlTool.name}`);
38
38
 
39
- ctx.registerTool(tools.listDatasourceTool );
39
+ ctx.registerTool(tools.listDatasourceTool, { name: tools.listDatasourceTool.name });
40
40
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${tools.listDatasourceTool.name}`);
41
41
 
42
42
  for (const lasTool of tools.lasTools) {
43
- ctx.registerTool(lasTool);
43
+ ctx.registerTool(lasTool, { name: lasTool.name });
44
44
  logger.info(`[${new Date().toISOString()}] [ContextLake] Tool registered: ${lasTool.name}`);
45
45
  }
46
46
 
@@ -57,7 +57,7 @@ export function registerAll(ctx: OpenClawPluginApi, logger: PluginLogger) {
57
57
  const contextlake = program.command('contextlake')
58
58
  .description('Manage ContextLake knowledge base');
59
59
 
60
- const commands = getCliCommands(pluginConfig, logger);
60
+ const commands = getCliCommands(pluginConfig, logger) as Record<string, any>;
61
61
 
62
62
  // Search
63
63
  contextlake.command('search <query>')
@@ -85,6 +85,33 @@ export function registerAll(ctx: OpenClawPluginApi, logger: PluginLogger) {
85
85
  .description('Configure credentials for ContextLake')
86
86
  .action(commands.onboardAction);
87
87
 
88
+ // S3 Tools
89
+ contextlake.command('list-s3-objects <url>')
90
+ .description('List objects in an S3-compatible bucket or local directory')
91
+ .option('--max-keys <number>', 'Maximum number of keys to return', '1000')
92
+ .option('--continuation-token <string>', 'Continuation token for pagination')
93
+ .action(commands.listS3ObjectsAction);
94
+
95
+ contextlake.command('read-s3-object <url>')
96
+ .description('Read the contents of an S3 object')
97
+ .option('--max-bytes <number>', 'Maximum number of bytes to read')
98
+ .action(commands.readS3ObjectAction);
99
+
100
+ contextlake.command('generate-presigned-url <url>')
101
+ .description('Generate a presigned HTTP URL for an S3/TOS object')
102
+ .option('--expires-in <number>', 'Expiration time in seconds', '3600')
103
+ .action(commands.generatePresignedUrlAction);
104
+
105
+ // LAS Tools
106
+ const tools = getAgentTools(pluginConfig, logger);
107
+ const lasTools = tools.lasTools;
108
+ for (const tool of lasTools) {
109
+ const cmdName = tool.name.replace(/_/g, '-');
110
+ contextlake.command(`${cmdName} <data>`)
111
+ .description(tool.label)
112
+ .action(commands[`${tool.name}Action`]);
113
+ }
114
+
88
115
  }, { commands: ['contextlake'] });
89
116
  logger.info(`[${new Date().toISOString()}] [ContextLake] CLI commands registered`);
90
117
  } catch (error: any) {
@@ -129,6 +156,38 @@ export function registerAll(ctx: OpenClawPluginApi, logger: PluginLogger) {
129
156
  handler: slashCommands.listDatasourceHandler
130
157
  });
131
158
 
159
+ ctx.registerCommand({
160
+ name: 'contextlake-list-s3-objects',
161
+ description: 'List objects in an S3-compatible bucket or local directory',
162
+ acceptsArgs: true,
163
+ handler: (slashCommands as any).listS3ObjectsHandler
164
+ });
165
+
166
+ ctx.registerCommand({
167
+ name: 'contextlake-read-s3-object',
168
+ description: 'Read the contents of an S3 object',
169
+ acceptsArgs: true,
170
+ handler: (slashCommands as any).readS3ObjectHandler
171
+ });
172
+
173
+ ctx.registerCommand({
174
+ name: 'contextlake-generate-presigned-url',
175
+ description: 'Generate a presigned HTTP URL for an S3/TOS object',
176
+ acceptsArgs: true,
177
+ handler: (slashCommands as any).generatePresignedUrlHandler
178
+ });
179
+
180
+ const tools = getAgentTools(pluginConfig, logger);
181
+ for (const tool of tools.lasTools) {
182
+ const cmdName = tool.name.replace(/_/g, '-');
183
+ ctx.registerCommand({
184
+ name: `contextlake-${cmdName}`,
185
+ description: tool.label,
186
+ acceptsArgs: true,
187
+ handler: (slashCommands as any)[`${tool.name}Handler`]
188
+ });
189
+ }
190
+
132
191
  logger.info(`[${new Date().toISOString()}] [ContextLake] Slash commands registered`);
133
192
  } catch (error: any) {
134
193
  logger.error(`[${new Date().toISOString()}] [ContextLake] Error registering Slash commands: ${error.message}${error.stack ? '\\n' + error.stack : ''}`);
@@ -2,13 +2,132 @@ import { ingestSource } from '../lib/actions/ingest';
2
2
  import { retrieveAssets } from '../lib/actions/retrieve';
3
3
  import { listAssets, deleteAssets } from '../lib/actions/manage';
4
4
  import { connectDataSource, listDataSources, ConnectParams } from '../lib/actions/profiler';
5
+ import { getLasTools } from '../lib/actions/las-tools';
6
+ import { listS3Objects, readS3Object, getPresignedUrl } from '../lib/actions/s3-tools';
5
7
  import { ContextLakeConfig } from '../utils/config';
6
8
  import * as fs from 'fs';
7
9
  import * as path from 'path';
8
10
  import * as os from 'os';
9
11
 
12
+ function parseOptionalInt(value: any, fallback: number): number {
13
+ const parsed = Number.parseInt(String(value), 10);
14
+ return Number.isFinite(parsed) ? parsed : fallback;
15
+ }
16
+
10
17
  export function getSlashCommands(pluginConfig: ContextLakeConfig, logger: any) {
18
+ const lasTools = getLasTools(pluginConfig, logger);
19
+ const lasHandlers: Record<string, any> = {};
20
+
21
+ for (const tool of lasTools) {
22
+ lasHandlers[`${tool.name}Handler`] = async (commandCtx: any) => {
23
+ const rawArgs = commandCtx.args || "";
24
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ${tool.name} started`, { args: rawArgs });
25
+ try {
26
+ if (!rawArgs.trim()) {
27
+ return { text: `**Error:** Missing arguments. Please provide JSON data or URL.` };
28
+ }
29
+
30
+ let data = {};
31
+ try {
32
+ data = JSON.parse(rawArgs);
33
+ } catch (e) {
34
+ data = { url: rawArgs.trim() };
35
+ }
36
+
37
+ let params = tool.name === 'las_bare_image_text_embedding'
38
+ ? data
39
+ : { data };
40
+
41
+ const result = await tool.execute('slash', params);
42
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command ${tool.name} completed`);
43
+ return { text: `**${tool.label} Results:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
44
+ } catch (e: any) {
45
+ logger.error(`[ContextLake] Slash ${tool.name} failed`, { error: e.message });
46
+ return { text: `**Error executing ${tool.label}:** ${e.message}` };
47
+ }
48
+ };
49
+ }
50
+
11
51
  return {
52
+ ...lasHandlers,
53
+
54
+ listS3ObjectsHandler: async (commandCtx: any) => {
55
+ const rawArgs = commandCtx.args || "";
56
+ const args = rawArgs.split(' ').filter((arg: string) => arg.trim() !== '');
57
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command list-s3-objects started`, { args });
58
+
59
+ try {
60
+ if (args.length === 0) {
61
+ return { text: `**Error:** Missing URL. Usage: /contextlake-list-s3-objects <url> [maxKeys]` };
62
+ }
63
+ let url = args[0];
64
+ const maxKeys = args.length > 1 ? parseOptionalInt(args[1], 1000) : 1000;
65
+
66
+ let prefix = '';
67
+ if (url && !url.startsWith('file://')) {
68
+ try {
69
+ const parsedUrl = new URL(url);
70
+ prefix = parsedUrl.pathname.replace(/^\//, '');
71
+ // Reconstruct url without path to pass to listS3Objects as base url
72
+ url = `${parsedUrl.protocol}//${parsedUrl.host}`;
73
+ } catch (e) {
74
+ // ignore, leave url as is
75
+ }
76
+ }
77
+
78
+ const result = await listS3Objects({ url }, prefix, maxKeys);
79
+ return { text: `**List S3 Objects Results:**\n\`\`\`json\n${JSON.stringify(result, null, 2)}\n\`\`\`` };
80
+ } catch (e: any) {
81
+ logger.error(`[ContextLake] Slash list-s3-objects failed`, { error: e.message });
82
+ return { text: `**Error executing list-s3-objects:** ${e.message}` };
83
+ }
84
+ },
85
+
86
+ readS3ObjectHandler: async (commandCtx: any) => {
87
+ const rawArgs = commandCtx.args || "";
88
+ const args = rawArgs.split(' ').filter((arg: string) => arg.trim() !== '');
89
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command read-s3-object started`, { args });
90
+
91
+ try {
92
+ if (args.length === 0) {
93
+ return { text: `**Error:** Missing URL. Usage: /contextlake-read-s3-object <url> [maxBytes]` };
94
+ }
95
+ const url = args[0];
96
+ const parsedUrl = new URL(url);
97
+ const key = parsedUrl.pathname.replace(/^\//, '');
98
+ const maxBytes = args.length > 1 ? parseOptionalInt(args[1], 0) : undefined;
99
+
100
+ const result = await readS3Object({ url }, key, maxBytes);
101
+ // Return base64 or string based on content? Returning string for simplicity in slash commands.
102
+ return { text: `**Read S3 Object Results:**\n\`\`\`\n${result.toString('utf-8')}\n\`\`\`` };
103
+ } catch (e: any) {
104
+ logger.error(`[ContextLake] Slash read-s3-object failed`, { error: e.message });
105
+ return { text: `**Error executing read-s3-object:** ${e.message}` };
106
+ }
107
+ },
108
+
109
+ generatePresignedUrlHandler: async (commandCtx: any) => {
110
+ const rawArgs = commandCtx.args || "";
111
+ const args = rawArgs.split(' ').filter((arg: string) => arg.trim() !== '');
112
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Slash command generate-presigned-url started`, { args });
113
+
114
+ try {
115
+ if (args.length === 0) {
116
+ return { text: `**Error:** Missing URL. Usage: /contextlake-generate-presigned-url <url> [expiresIn]` };
117
+ }
118
+ const url = args[0];
119
+ const parsedUrl = new URL(url);
120
+ const key = parsedUrl.pathname.replace(/^\//, '');
121
+ const expiresIn = args.length > 1 ? parseOptionalInt(args[1], 3600) : 3600;
122
+
123
+ const result = await getPresignedUrl({ url }, key, expiresIn);
124
+ return { text: `**Presigned URL:**\n${result}` };
125
+ } catch (e: any) {
126
+ logger.error(`[ContextLake] Slash generate-presigned-url failed`, { error: e.message });
127
+ return { text: `**Error executing generate-presigned-url:** ${e.message}` };
128
+ }
129
+ },
130
+
12
131
  listHandler: async (commandCtx: any) => {
13
132
  const rawArgs = commandCtx.args || "";
14
133
  const args = rawArgs.split(' ').filter((arg: string) => arg.trim() !== '');
@@ -36,7 +36,7 @@ export function getAgentTools(pluginConfig: ContextLakeConfig, logger: any): {
36
36
  additionalProperties: false
37
37
  },
38
38
  async execute(toolCallId: string, params: any) {
39
- logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list-datasource skill, toolCallId: ${toolCallId}`);
39
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list-datasource tool, toolCallId: ${toolCallId}`);
40
40
  try {
41
41
  const result = await listDataSources();
42
42
  return {
@@ -44,7 +44,7 @@ export function getAgentTools(pluginConfig: ContextLakeConfig, logger: any): {
44
44
  details: result
45
45
  } as any;
46
46
  } catch (error: any) {
47
- logger.error(`[${new Date().toISOString()}] [ContextLake] list-datasource skill failed`, { error: error.message });
47
+ logger.error(`[${new Date().toISOString()}] [ContextLake] list-datasource tool failed`, { error: error.message });
48
48
  return {
49
49
  content: [{ type: "text", text: String(error.message) }],
50
50
  details: { error: error.message }
@@ -77,7 +77,7 @@ Example User Queries:
77
77
  },
78
78
 
79
79
  async execute(toolCallId: string, params: any) {
80
- logger.info(`[${new Date().toISOString()}] [ContextLake] Executing retrieve skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
80
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing retrieve tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
81
81
 
82
82
  try {
83
83
  let actualParams = params;
@@ -101,13 +101,13 @@ Example User Queries:
101
101
  }
102
102
 
103
103
  const result = await retrieveAssets(actualParams, pluginConfig, logger);
104
- logger.info(`[${new Date().toISOString()}] [ContextLake] Retrieve skill completed`, { resultCount: Array.isArray(result) ? result.length : 0 });
104
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Retrieve tool completed`, { resultCount: Array.isArray(result) ? result.length : 0 });
105
105
  return {
106
106
  content: [{ type: "text", text: JSON.stringify(result) }],
107
107
  details: result
108
108
  } as any;
109
109
  } catch (error: any) {
110
- logger.error(`[${new Date().toISOString()}] [ContextLake] Retrieve skill failed`, { error: error.message, stack: error.stack });
110
+ logger.error(`[${new Date().toISOString()}] [ContextLake] Retrieve tool failed`, { error: error.message, stack: error.stack });
111
111
  return {
112
112
  content: [{ type: "text", text: String(error.message
113
113
  ) }],
@@ -137,7 +137,7 @@ Example User Queries:
137
137
  },
138
138
 
139
139
  async execute(toolCallId: string, params: any) {
140
- logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
140
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
141
141
 
142
142
  try {
143
143
  let actualParams = params;
@@ -145,13 +145,13 @@ Example User Queries:
145
145
  actualParams = params.params;
146
146
  }
147
147
  const result = await listAssets(actualParams, pluginConfig, logger);
148
- logger.info(`[${new Date().toISOString()}] [ContextLake] List skill completed`, { count: Array.isArray(result) ? result.length : 0 });
148
+ logger.info(`[${new Date().toISOString()}] [ContextLake] List tool completed`, { count: Array.isArray(result) ? result.length : 0 });
149
149
  return {
150
150
  content: [{ type: "text", text: JSON.stringify(result) }],
151
151
  details: result
152
152
  } as any;
153
153
  } catch (error: any) {
154
- logger.error(`[${new Date().toISOString()}] [ContextLake] List skill failed`, { error: error.message, stack: error.stack });
154
+ logger.error(`[${new Date().toISOString()}] [ContextLake] List tool failed`, { error: error.message, stack: error.stack });
155
155
  return {
156
156
  content: [{ type: "text", text: String(error.message
157
157
  ) }],
@@ -183,7 +183,7 @@ Example User Queries:
183
183
  },
184
184
 
185
185
  async execute(toolCallId: string, params: any) {
186
- logger.info(`[${new Date().toISOString()}] [ContextLake] Executing delete skill, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
186
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing delete tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
187
187
 
188
188
  try {
189
189
  let actualParams = params;
@@ -191,13 +191,13 @@ Example User Queries:
191
191
  actualParams = params.params;
192
192
  }
193
193
  const result = await deleteAssets(actualParams, pluginConfig, logger);
194
- logger.info(`[${new Date().toISOString()}] [ContextLake] Delete skill completed`, { result });
194
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Delete tool completed`, { result });
195
195
  return {
196
196
  content: [{ type: "text", text: JSON.stringify(result) }],
197
197
  details: result
198
198
  } as any;
199
199
  } catch (error: any) {
200
- logger.error(`[${new Date().toISOString()}] [ContextLake] Delete skill failed`, { error: error.message, stack: error.stack });
200
+ logger.error(`[${new Date().toISOString()}] [ContextLake] Delete tool failed`, { error: error.message, stack: error.stack });
201
201
  return {
202
202
  content: [{ type: "text", text: String(error.message
203
203
  ) }],
@@ -226,6 +226,7 @@ Example User Queries:
226
226
  additionalProperties: false
227
227
  },
228
228
  async execute(toolCallId: string, params: any) {
229
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing list-s3-objects tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
229
230
  let actualParams = params.params || params;
230
231
  try {
231
232
  const result = await listS3Objects(actualParams, actualParams.prefix || '', actualParams.maxKeys, actualParams.continuationToken);
@@ -253,6 +254,7 @@ Example User Queries:
253
254
  additionalProperties: false
254
255
  },
255
256
  async execute(toolCallId: string, params: any) {
257
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing read-s3-object tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
256
258
  let actualParams = params.params || params;
257
259
  try {
258
260
  // Extract key from url if provided
@@ -299,6 +301,7 @@ Example User Queries:
299
301
  additionalProperties: false
300
302
  },
301
303
  async execute(toolCallId: string, params: any) {
304
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing generate-presigned-url tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
302
305
  let actualParams = params.params || params;
303
306
  try {
304
307
  let key = actualParams.key;
@@ -339,6 +342,7 @@ Example User Queries:
339
342
  additionalProperties: false
340
343
  },
341
344
  async execute(toolCallId: string, params: any) {
345
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing write-lance-catalog tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
342
346
  let actualParams = params.params || params;
343
347
  try {
344
348
  await writeLanceCatalog(actualParams);
@@ -364,6 +368,7 @@ Example User Queries:
364
368
  additionalProperties: false
365
369
  },
366
370
  async execute(toolCallId: string, params: any) {
371
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing read-lance-catalog tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
367
372
  let actualParams = params.params || params;
368
373
  try {
369
374
  const results = await readLanceCatalog(actualParams);
@@ -60,6 +60,7 @@ Parameters in data:
60
60
  required: ['data']
61
61
  },
62
62
  async execute(toolCallId: string, params: any) {
63
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_image_resample tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
63
64
  if (params.data?.image) {
64
65
  params.data.image = await processUrl(params.data.image);
65
66
  }
@@ -83,6 +84,7 @@ Parameters in data:
83
84
  required: ['data']
84
85
  },
85
86
  async execute(toolCallId: string, params: any) {
87
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_audio_extract_and_split tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
86
88
  if (params.data?.input_path) {
87
89
  params.data.input_path = await processUrl(params.data.input_path);
88
90
  }
@@ -104,6 +106,7 @@ Parameters in data:
104
106
  required: ['data']
105
107
  },
106
108
  async execute(toolCallId: string, params: any) {
109
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_audio_convert tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
107
110
  if (params.data?.input_path) {
108
111
  params.data.input_path = await processUrl(params.data.input_path);
109
112
  }
@@ -125,6 +128,7 @@ Parameters in data:
125
128
  required: ['data']
126
129
  },
127
130
  async execute(toolCallId: string, params: any) {
131
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_asr_pro tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
128
132
  if (params.data?.audio?.url) {
129
133
  params.data.audio.url = await processUrl(params.data.audio.url);
130
134
  }
@@ -144,6 +148,7 @@ Parameters in data:
144
148
  required: ['data']
145
149
  },
146
150
  async execute(toolCallId: string, params: any) {
151
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_seed_2_0 tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
147
152
  if (params.data?.audio?.url) {
148
153
  params.data.audio.url = await processUrl(params.data.audio.url);
149
154
  }
@@ -170,6 +175,7 @@ Parameters:
170
175
  required: ['model', 'input']
171
176
  },
172
177
  async execute(toolCallId: string, params: any) {
178
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_bare_image_text_embedding tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
173
179
  if (params.input && Array.isArray(params.input)) {
174
180
  for (const item of params.input) {
175
181
  if (item.type === 'image_url' && item.image_url?.url) {
@@ -200,6 +206,7 @@ Parameters in data:
200
206
  required: ['data']
201
207
  },
202
208
  async execute(toolCallId: string, params: any) {
209
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_long_video_understand tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
203
210
  if (params.data?.video_url) {
204
211
  params.data.video_url = await processUrl(params.data.video_url);
205
212
  }
@@ -221,6 +228,7 @@ Parameters in data:
221
228
  required: ['data']
222
229
  },
223
230
  async execute(toolCallId: string, params: any) {
231
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_pdf_parse_doubao tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
224
232
  if (params.data?.url) {
225
233
  params.data.url = await processUrl(params.data.url);
226
234
  }
@@ -242,6 +250,7 @@ Parameters in data:
242
250
  required: ['data']
243
251
  },
244
252
  async execute(toolCallId: string, params: any) {
253
+ logger.info(`[${new Date().toISOString()}] [ContextLake] Executing las_video_resize tool, toolCallId: ${toolCallId}`, { params: JSON.stringify(params) });
245
254
  if (params.data?.video_url) {
246
255
  params.data.video_url = await processUrl(params.data.video_url);
247
256
  }