UNPKG

@coretext-ai/qa-looker-b5c6d7e8-f9a0-4123-a456-567890123456

Version:
1,177 lines 49.7 kB
import { Logger } from '../services/logger.js'; export class LookerTools { constructor(client) { this.initialized = false; this.client = client; // Get logger from client if available, otherwise create fallback this.logger = client.logger || new Logger({ logLevel: 'ERROR', component: 'tools', enableConsole: true, enableShipping: false, serverName: '' }); } async ensureInitialized() { if (!this.initialized) { // Log tools initialization now that client is ready this.logger.info('TOOLS_INIT', 'Tools instance initialization started', { integration: 'looker', isOAuth: false }); this.logger.info('CLIENT_INITIALIZATION', 'Starting client initialization', { isOAuth: false }); this.initialized = true; this.logger.info('CLIENT_INITIALIZATION', 'Client initialization completed', { initialized: this.initialized }); } } getToolDefinitions() { return [ { name: 'looker_login', description: 'Authenticate with Looker API using client credentials and obtain access token', inputSchema: { type: 'object', properties: { client_id: { type: 'string', description: 'Client ID from Looker API credentials' }, client_secret: { type: 'string', description: 'Client secret from Looker API credentials' }, }, required: ['client_id', 'client_secret'] } }, { name: 'looker_logout', description: 'Invalidate current access token and logout', inputSchema: { type: 'object', properties: {}, required: [] } }, { name: 'looker_me', description: 'Get current user information', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return (e.g., 'id,first_name,last_name,display_name,email')' }, }, required: [] } }, { name: 'looker_list_users', description: 'Get all users in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, sorts: { type: 'string', description: 'Fields to sort by (e.g. 'id', 'first_name')' }, }, required: [] } }, { name: 'looker_create_user', description: 'Create a new user in Looker', inputSchema: { type: 'object', properties: { first_name: { type: 'string', description: 'User's first name' }, last_name: { type: 'string', description: 'User's last name' }, email: { type: 'string', description: 'User's email address' }, is_disabled: { type: 'boolean', description: 'Whether the user is disabled' }, models_dir_validated: { type: 'boolean', description: 'Whether models directory is validated' }, }, required: ['first_name', 'last_name', 'email',] } }, { name: 'looker_update_user', description: 'Update user information', inputSchema: { type: 'object', properties: { user_id: { type: 'string', description: 'User ID to update' }, first_name: { type: 'string', description: 'User's first name' }, last_name: { type: 'string', description: 'User's last name' }, email: { type: 'string', description: 'User's email address' }, is_disabled: { type: 'boolean', description: 'Whether the user is disabled' }, }, required: ['user_id',] } }, { name: 'looker_list_dashboards', description: 'Get all dashboards in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, sorts: { type: 'string', description: 'Fields to sort by' }, }, required: [] } }, { name: 'looker_get_dashboard', description: 'Get dashboard information by ID', inputSchema: { type: 'object', properties: { dashboard_id: { type: 'string', description: 'Dashboard ID to retrieve' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['dashboard_id',] } }, { name: 'looker_create_dashboard', description: 'Create a new dashboard', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Dashboard title' }, description: { type: 'string', description: 'Dashboard description' }, hidden: { type: 'boolean', description: 'Whether the dashboard is hidden' }, refresh_interval: { type: 'string', description: 'Refresh interval for dashboard' }, }, required: ['title',] } }, { name: 'looker_update_dashboard', description: 'Update dashboard properties', inputSchema: { type: 'object', properties: { dashboard_id: { type: 'string', description: 'Dashboard ID to update' }, title: { type: 'string', description: 'Dashboard title' }, description: { type: 'string', description: 'Dashboard description' }, hidden: { type: 'boolean', description: 'Whether the dashboard is hidden' }, }, required: ['dashboard_id',] } }, { name: 'looker_delete_dashboard', description: 'Delete a dashboard', inputSchema: { type: 'object', properties: { dashboard_id: { type: 'string', description: 'Dashboard ID to delete' }, }, required: ['dashboard_id'] } }, { name: 'looker_list_looks', description: 'Get all looks (saved queries) in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, sorts: { type: 'string', description: 'Fields to sort by' }, }, required: [] } }, { name: 'looker_get_look', description: 'Get look (saved query) information by ID', inputSchema: { type: 'object', properties: { look_id: { type: 'string', description: 'Look ID to retrieve' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['look_id',] } }, { name: 'looker_run_look', description: 'Run a look and return results in specified format', inputSchema: { type: 'object', properties: { look_id: { type: 'string', description: 'Look ID to run' }, result_format: { type: 'string', description: 'Result format: json, csv, xlsx, html, md, txt, png, jpg' }, limit: { type: 'number', description: 'Row limit for results (-1 for unlimited)' }, apply_formatting: { type: 'boolean', description: 'Apply formatting to results' }, apply_vis: { type: 'boolean', description: 'Apply visualization to results' }, }, required: ['look_id', 'result_format',] } }, { name: 'looker_create_look', description: 'Create a new look (saved query)', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Look title' }, description: { type: 'string', description: 'Look description' }, public: { type: 'boolean', description: 'Whether the look is public' }, query_id: { type: 'string', description: 'Query ID to associate with the look' }, }, required: ['title', 'query_id'] } }, { name: 'looker_list_queries', description: 'Get all queries in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, sorts: { type: 'string', description: 'Fields to sort by' }, }, required: [] } }, { name: 'looker_get_query', description: 'Get query information by ID', inputSchema: { type: 'object', properties: { query_id: { type: 'string', description: 'Query ID to retrieve' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['query_id',] } }, { name: 'looker_create_query', description: 'Create a new query', inputSchema: { type: 'object', properties: { model: { type: 'string', description: 'Model name for the query' }, explore: { type: 'string', description: 'Explore name for the query' }, dimensions: { type: 'array', description: 'Array of dimension names to include' }, measures: { type: 'array', description: 'Array of measure names to include' }, filters: { type: 'object', description: 'Object containing filter conditions' }, sorts: { type: 'array', description: 'Array of sort specifications' }, limit: { type: 'string', description: 'Row limit for the query' }, }, required: ['model', 'explore',] } }, { name: 'looker_run_query', description: 'Run a query and return results in specified format', inputSchema: { type: 'object', properties: { query_id: { type: 'string', description: 'Query ID to run' }, result_format: { type: 'string', description: 'Result format: json, csv, xlsx, html, md, txt, png, jpg' }, limit: { type: 'number', description: 'Row limit for results (-1 for unlimited)' }, apply_formatting: { type: 'boolean', description: 'Apply formatting to results' }, apply_vis: { type: 'boolean', description: 'Apply visualization to results' }, cache: { type: 'boolean', description: 'Whether to use cached results' }, }, required: ['query_id', 'result_format',] } }, { name: 'looker_run_inline_query', description: 'Run an inline query without saving it first', inputSchema: { type: 'object', properties: { result_format: { type: 'string', description: 'Result format: json, csv, xlsx, html, md, txt, png, jpg' }, model: { type: 'string', description: 'Model name for the query' }, explore: { type: 'string', description: 'Explore name for the query' }, dimensions: { type: 'array', description: 'Array of dimension names to include' }, measures: { type: 'array', description: 'Array of measure names to include' }, filters: { type: 'object', description: 'Object containing filter conditions' }, sorts: { type: 'array', description: 'Array of sort specifications' }, limit: { type: 'string', description: 'Row limit for the query' }, }, required: ['result_format', 'model', 'explore',] } }, { name: 'looker_list_spaces', description: 'Get all spaces in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, sorts: { type: 'string', description: 'Fields to sort by' }, }, required: [] } }, { name: 'looker_get_space', description: 'Get space information by ID', inputSchema: { type: 'object', properties: { space_id: { type: 'string', description: 'Space ID to retrieve' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['space_id',] } }, { name: 'looker_create_space', description: 'Create a new space', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Space name' }, parent_id: { type: 'string', description: 'Parent space ID' }, }, required: ['name',] } }, { name: 'looker_list_folders', description: 'Get all folders in the Looker instance', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, }, required: [] } }, { name: 'looker_get_folder', description: 'Get folder information by ID', inputSchema: { type: 'object', properties: { folder_id: { type: 'string', description: 'Folder ID to retrieve' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['folder_id',] } }, { name: 'looker_create_folder', description: 'Create a new folder', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Folder name' }, parent_id: { type: 'string', description: 'Parent folder ID' }, }, required: ['name',] } }, { name: 'looker_create_query_task', description: 'Create and run a query task asynchronously', inputSchema: { type: 'object', properties: { query_id: { type: 'string', description: 'Query ID to run' }, result_format: { type: 'string', description: 'Result format: json, csv, xlsx, html, md, txt, png, jpg' }, limit: { type: 'number', description: 'Row limit (may override the limit in the saved query)' }, apply_formatting: { type: 'boolean', description: 'Apply model-specified formatting to each result' }, apply_vis: { type: 'boolean', description: 'Apply visualization options to results' }, cache: { type: 'boolean', description: 'Get results from cache if available' }, generate_drill_links: { type: 'boolean', description: 'Generate drill links (only applicable to 'json_detail' format)' }, force_production: { type: 'boolean', description: 'Force use of production models even if the user is in development mode' }, cache_only: { type: 'boolean', description: 'Retrieve any results from cache even if the results have expired' }, }, required: ['result_format',] } }, { name: 'looker_get_query_task', description: 'Get query task status and results', inputSchema: { type: 'object', properties: { query_task_id: { type: 'string', description: 'Query task ID' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['query_task_id',] } }, { name: 'looker_get_query_task_results', description: 'Get query task results', inputSchema: { type: 'object', properties: { query_task_id: { type: 'string', description: 'Query task ID' }, }, required: ['query_task_id'] } }, { name: 'looker_list_models', description: 'Get all LookML models', inputSchema: { type: 'object', properties: { fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: [] } }, { name: 'looker_get_model', description: 'Get LookML model by name', inputSchema: { type: 'object', properties: { model_name: { type: 'string', description: 'Model name' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['model_name',] } }, { name: 'looker_list_explores', description: 'Get all explores for a model', inputSchema: { type: 'object', properties: { model_name: { type: 'string', description: 'Model name' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['model_name',] } }, { name: 'looker_get_explore', description: 'Get explore metadata for a model', inputSchema: { type: 'object', properties: { model_name: { type: 'string', description: 'Model name' }, explore_name: { type: 'string', description: 'Explore name' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: ['model_name', 'explore_name',] } }, { name: 'looker_search_dashboards', description: 'Search dashboards', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Match dashboard title' }, description: { type: 'string', description: 'Match dashboard description' }, content_favorite_id: { type: 'string', description: 'Filter by content favorite ID' }, space_id: { type: 'string', description: 'Filter by space ID' }, deleted: { type: 'boolean', description: 'Include deleted dashboards' }, page: { type: 'number', description: 'Page number for pagination' }, per_page: { type: 'number', description: 'Number of results per page (max 1000)' }, fields: { type: 'string', description: 'Comma-separated list of fields to return' }, }, required: [] } }, { name: 'looker_render_task_results', description: 'Get render task results (binary content)', inputSchema: { type: 'object', properties: { render_task_id: { type: 'string', description: 'Render task ID' }, }, required: ['render_task_id'] } } ]; } canHandle(toolName) { const supportedTools = [ 'looker_login', 'looker_logout', 'looker_me', 'looker_list_users', 'looker_create_user', 'looker_update_user', 'looker_list_dashboards', 'looker_get_dashboard', 'looker_create_dashboard', 'looker_update_dashboard', 'looker_delete_dashboard', 'looker_list_looks', 'looker_get_look', 'looker_run_look', 'looker_create_look', 'looker_list_queries', 'looker_get_query', 'looker_create_query', 'looker_run_query', 'looker_run_inline_query', 'looker_list_spaces', 'looker_get_space', 'looker_create_space', 'looker_list_folders', 'looker_get_folder', 'looker_create_folder', 'looker_create_query_task', 'looker_get_query_task', 'looker_get_query_task_results', 'looker_list_models', 'looker_get_model', 'looker_list_explores', 'looker_get_explore', 'looker_search_dashboards', 'looker_render_task_results' ]; return supportedTools.includes(toolName); } async executeTool(name, args) { const startTime = Date.now(); this.logger.logToolStart(name, args); await this.ensureInitialized(); // Validate tool is supported if (!this.canHandle(name)) { this.logger.error('TOOL_ERROR', 'Unknown tool requested', { tool: name, supportedTools: ['looker_login', 'looker_logout', 'looker_me', 'looker_list_users', 'looker_create_user', 'looker_update_user', 'looker_list_dashboards', 'looker_get_dashboard', 'looker_create_dashboard', 'looker_update_dashboard', 'looker_delete_dashboard', 'looker_list_looks', 'looker_get_look', 'looker_run_look', 'looker_create_look', 'looker_list_queries', 'looker_get_query', 'looker_create_query', 'looker_run_query', 'looker_run_inline_query', 'looker_list_spaces', 'looker_get_space', 'looker_create_space', 'looker_list_folders', 'looker_get_folder', 'looker_create_folder', 'looker_create_query_task', 'looker_get_query_task', 'looker_get_query_task_results', 'looker_list_models', 'looker_get_model', 'looker_list_explores', 'looker_get_explore', 'looker_search_dashboards', 'looker_render_task_results'] }); throw new Error(`Unknown tool: ${name}`); } // Validate required parameters this.logger.debug('PARAM_VALIDATION', 'Validating tool parameters', { tool: name, providedArgs: Object.keys(args || {}) }); try { let result; switch (name) { case 'looker_login': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_login', clientMethod: 'login' }); result = await this.client.login(args); break; case 'looker_logout': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_logout', clientMethod: 'logout' }); result = await this.client.logout(args); break; case 'looker_me': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_me', clientMethod: 'me' }); result = await this.client.me(args); break; case 'looker_list_users': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_users', clientMethod: 'listUsers' }); result = await this.client.listUsers(args); break; case 'looker_create_user': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_user', clientMethod: 'createUser' }); result = await this.client.createUser(args); break; case 'looker_update_user': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_update_user', clientMethod: 'updateUser' }); result = await this.client.updateUser(args); break; case 'looker_list_dashboards': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_dashboards', clientMethod: 'listDashboards' }); result = await this.client.listDashboards(args); break; case 'looker_get_dashboard': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_dashboard', clientMethod: 'getDashboard' }); result = await this.client.getDashboard(args); break; case 'looker_create_dashboard': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_dashboard', clientMethod: 'createDashboard' }); result = await this.client.createDashboard(args); break; case 'looker_update_dashboard': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_update_dashboard', clientMethod: 'updateDashboard' }); result = await this.client.updateDashboard(args); break; case 'looker_delete_dashboard': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_delete_dashboard', clientMethod: 'deleteDashboard' }); result = await this.client.deleteDashboard(args); break; case 'looker_list_looks': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_looks', clientMethod: 'listLooks' }); result = await this.client.listLooks(args); break; case 'looker_get_look': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_look', clientMethod: 'getLook' }); result = await this.client.getLook(args); break; case 'looker_run_look': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_run_look', clientMethod: 'runLook' }); result = await this.client.runLook(args); break; case 'looker_create_look': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_look', clientMethod: 'createLook' }); result = await this.client.createLook(args); break; case 'looker_list_queries': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_queries', clientMethod: 'listQueries' }); result = await this.client.listQueries(args); break; case 'looker_get_query': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_query', clientMethod: 'getQuery' }); result = await this.client.getQuery(args); break; case 'looker_create_query': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_query', clientMethod: 'createQuery' }); result = await this.client.createQuery(args); break; case 'looker_run_query': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_run_query', clientMethod: 'runQuery' }); result = await this.client.runQuery(args); break; case 'looker_run_inline_query': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_run_inline_query', clientMethod: 'runInlineQuery' }); result = await this.client.runInlineQuery(args); break; case 'looker_list_spaces': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_spaces', clientMethod: 'listSpaces' }); result = await this.client.listSpaces(args); break; case 'looker_get_space': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_space', clientMethod: 'getSpace' }); result = await this.client.getSpace(args); break; case 'looker_create_space': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_space', clientMethod: 'createSpace' }); result = await this.client.createSpace(args); break; case 'looker_list_folders': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_folders', clientMethod: 'listFolders' }); result = await this.client.listFolders(args); break; case 'looker_get_folder': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_folder', clientMethod: 'getFolder' }); result = await this.client.getFolder(args); break; case 'looker_create_folder': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_folder', clientMethod: 'createFolder' }); result = await this.client.createFolder(args); break; case 'looker_create_query_task': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_create_query_task', clientMethod: 'createQueryTask' }); result = await this.client.createQueryTask(args); break; case 'looker_get_query_task': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_query_task', clientMethod: 'getQueryTask' }); result = await this.client.getQueryTask(args); break; case 'looker_get_query_task_results': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_query_task_results', clientMethod: 'getQueryTaskResults' }); result = await this.client.getQueryTaskResults(args); break; case 'looker_list_models': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_models', clientMethod: 'listModels' }); result = await this.client.listModels(args); break; case 'looker_get_model': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_model', clientMethod: 'getModel' }); result = await this.client.getModel(args); break; case 'looker_list_explores': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_list_explores', clientMethod: 'listExplores' }); result = await this.client.listExplores(args); break; case 'looker_get_explore': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_get_explore', clientMethod: 'getExplore' }); result = await this.client.getExplore(args); break; case 'looker_search_dashboards': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_search_dashboards', clientMethod: 'searchDashboards' }); result = await this.client.searchDashboards(args); break; case 'looker_render_task_results': this.logger.debug('TOOL_EXECUTE', 'Calling client method', { tool: 'looker_render_task_results', clientMethod: 'renderTaskResults' }); result = await this.client.renderTaskResults(args); break; default: throw new Error(`Unknown tool: ${name}`); } const duration = Date.now() - startTime; this.logger.logToolSuccess(name, duration, result); // Return raw result for non-OAuth templates return result; } catch (error) { const duration = Date.now() - startTime; const errorMessage = error instanceof Error ? error.message : String(error); this.logger.logToolError(name, error, duration, args); throw error; } } } //# sourceMappingURL=looker-tools.js.map