diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 16c248b74d..1d50d0d068 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -5819,3 +5819,15 @@ export function RedisIcon(props: SVGProps) { ) } + +export function HexIcon(props: SVGProps) { + return ( + + + + ) +} diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 061586caee..5929ccca3d 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -54,6 +54,7 @@ import { GrafanaIcon, GrainIcon, GreptileIcon, + HexIcon, HubspotIcon, HuggingFaceIcon, HunterIOIcon, @@ -196,6 +197,7 @@ export const blockTypeToIconMap: Record = { grafana: GrafanaIcon, grain: GrainIcon, greptile: GreptileIcon, + hex: HexIcon, hubspot: HubspotIcon, huggingface: HuggingFaceIcon, hunter: HunterIOIcon, diff --git a/apps/docs/content/docs/en/tools/hex.mdx b/apps/docs/content/docs/en/tools/hex.mdx new file mode 100644 index 0000000000..c979333847 --- /dev/null +++ b/apps/docs/content/docs/en/tools/hex.mdx @@ -0,0 +1,459 @@ +--- +title: Hex +description: Run and manage Hex projects +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +{/* MANUAL-CONTENT-START:intro */} +[Hex](https://hex.tech/) is a collaborative platform for analytics and data science that allows you to build, run, and share interactive data projects and notebooks. Hex lets teams work together on data exploration, transformation, and visualization, making it easy to turn analysis into shareable insights. + +With Hex, you can: + +- **Create and run powerful notebooks**: Blend SQL, Python, and visualizations in a single, interactive workspace. +- **Collaborate and share**: Work together with teammates in real time and publish interactive data apps for broader audiences. +- **Automate and orchestrate workflows**: Schedule notebook runs, parameterize runs with inputs, and automate data tasks. +- **Visualize and communicate results**: Turn analysis results into dashboards or interactive apps that anyone can use. +- **Integrate with your data stack**: Connect easily to data warehouses, APIs, and other sources. + +The Sim Hex integration allows your AI agents or workflows to: + +- List, get, and manage Hex projects directly from Sim. +- Trigger and monitor notebook runs, check their statuses, or cancel them as part of larger automation flows. +- Retrieve run results and use them within Sim-powered processes and decision-making. +- Leverage Hex’s interactive analytics capabilities right inside your automated Sim workflows. + +Whether you’re empowering analysts, automating reporting, or embedding actionable data into your processes, Hex and Sim provide a seamless way to operationalize analytics and bring data-driven insights to your team. +{/* MANUAL-CONTENT-END */} + + +## Usage Instructions + +Integrate Hex into your workflow. Run projects, check run status, manage collections and groups, list users, and view data connections. Requires a Hex API token. + + + +## Tools + +### `hex_cancel_run` + +Cancel an active Hex project run. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project | +| `runId` | string | Yes | The UUID of the run to cancel | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Whether the run was successfully cancelled | +| `projectId` | string | Project UUID | +| `runId` | string | Run UUID that was cancelled | + +### `hex_create_collection` + +Create a new collection in the Hex workspace to organize projects. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `name` | string | Yes | Name for the new collection | +| `description` | string | No | Optional description for the collection | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Newly created collection UUID | +| `name` | string | Collection name | +| `description` | string | Collection description | +| `creator` | object | Collection creator | +| ↳ `email` | string | Creator email | +| ↳ `id` | string | Creator UUID | + +### `hex_get_collection` + +Retrieve details for a specific Hex collection by its ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `collectionId` | string | Yes | The UUID of the collection | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Collection UUID | +| `name` | string | Collection name | +| `description` | string | Collection description | +| `creator` | object | Collection creator | +| ↳ `email` | string | Creator email | +| ↳ `id` | string | Creator UUID | + +### `hex_get_data_connection` + +Retrieve details for a specific data connection including type, description, and configuration flags. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `dataConnectionId` | string | Yes | The UUID of the data connection | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Connection UUID | +| `name` | string | Connection name | +| `type` | string | Connection type \(e.g., snowflake, postgres, bigquery\) | +| `description` | string | Connection description | +| `connectViaSsh` | boolean | Whether SSH tunneling is enabled | +| `includeMagic` | boolean | Whether Magic AI features are enabled | +| `allowWritebackCells` | boolean | Whether writeback cells are allowed | + +### `hex_get_group` + +Retrieve details for a specific Hex group. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `groupId` | string | Yes | The UUID of the group | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Group UUID | +| `name` | string | Group name | +| `createdAt` | string | Creation timestamp | + +### `hex_get_project` + +Get metadata and details for a specific Hex project by its ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Project UUID | +| `title` | string | Project title | +| `description` | string | Project description | +| `status` | object | Project status | +| ↳ `name` | string | Status name \(e.g., PUBLISHED, DRAFT\) | +| `type` | string | Project type \(PROJECT or COMPONENT\) | +| `creator` | object | Project creator | +| ↳ `email` | string | Creator email | +| `owner` | object | Project owner | +| ↳ `email` | string | Owner email | +| `categories` | array | Project categories | +| ↳ `name` | string | Category name | +| ↳ `description` | string | Category description | +| `lastEditedAt` | string | ISO 8601 last edited timestamp | +| `lastPublishedAt` | string | ISO 8601 last published timestamp | +| `createdAt` | string | ISO 8601 creation timestamp | +| `archivedAt` | string | ISO 8601 archived timestamp | +| `trashedAt` | string | ISO 8601 trashed timestamp | + +### `hex_get_project_runs` + +Retrieve API-triggered runs for a Hex project with optional filtering by status and pagination. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project | +| `limit` | number | No | Maximum number of runs to return \(1-100, default: 25\) | +| `offset` | number | No | Offset for paginated results \(default: 0\) | +| `statusFilter` | string | No | Filter by run status: PENDING, RUNNING, ERRORED, COMPLETED, KILLED, UNABLE_TO_ALLOCATE_KERNEL | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `runs` | array | List of project runs | +| ↳ `projectId` | string | Project UUID | +| ↳ `runId` | string | Run UUID | +| ↳ `runUrl` | string | URL to view the run | +| ↳ `status` | string | Run status \(PENDING, RUNNING, COMPLETED, ERRORED, KILLED, UNABLE_TO_ALLOCATE_KERNEL\) | +| ↳ `startTime` | string | Run start time | +| ↳ `endTime` | string | Run end time | +| ↳ `elapsedTime` | number | Elapsed time in seconds | +| ↳ `traceId` | string | Trace ID | +| ↳ `projectVersion` | number | Project version number | +| `total` | number | Total number of runs returned | +| `traceId` | string | Top-level trace ID | + +### `hex_get_queried_tables` + +Return the warehouse tables queried by a Hex project, including data connection and table names. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project | +| `limit` | number | No | Maximum number of tables to return \(1-100\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `tables` | array | List of warehouse tables queried by the project | +| ↳ `dataConnectionId` | string | Data connection UUID | +| ↳ `dataConnectionName` | string | Data connection name | +| ↳ `tableName` | string | Table name | +| `total` | number | Total number of tables returned | + +### `hex_get_run_status` + +Check the status of a Hex project run by its run ID. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project | +| `runId` | string | Yes | The UUID of the run to check | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `projectId` | string | Project UUID | +| `runId` | string | Run UUID | +| `runUrl` | string | URL to view the run | +| `status` | string | Run status \(PENDING, RUNNING, COMPLETED, ERRORED, KILLED, UNABLE_TO_ALLOCATE_KERNEL\) | +| `startTime` | string | ISO 8601 run start time | +| `endTime` | string | ISO 8601 run end time | +| `elapsedTime` | number | Elapsed time in seconds | +| `traceId` | string | Trace ID for debugging | +| `projectVersion` | number | Project version number | + +### `hex_list_collections` + +List all collections in the Hex workspace. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `limit` | number | No | Maximum number of collections to return \(1-500, default: 25\) | +| `sortBy` | string | No | Sort by field: NAME | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `collections` | array | List of collections | +| ↳ `id` | string | Collection UUID | +| ↳ `name` | string | Collection name | +| ↳ `description` | string | Collection description | +| ↳ `creator` | object | Collection creator | +| ↳ `email` | string | Creator email | +| ↳ `id` | string | Creator UUID | +| `total` | number | Total number of collections returned | + +### `hex_list_data_connections` + +List all data connections in the Hex workspace (e.g., Snowflake, PostgreSQL, BigQuery). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `limit` | number | No | Maximum number of connections to return \(1-500, default: 25\) | +| `sortBy` | string | No | Sort by field: CREATED_AT or NAME | +| `sortDirection` | string | No | Sort direction: ASC or DESC | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `connections` | array | List of data connections | +| ↳ `id` | string | Connection UUID | +| ↳ `name` | string | Connection name | +| ↳ `type` | string | Connection type \(e.g., athena, bigquery, databricks, postgres, redshift, snowflake\) | +| ↳ `description` | string | Connection description | +| ↳ `connectViaSsh` | boolean | Whether SSH tunneling is enabled | +| ↳ `includeMagic` | boolean | Whether Magic AI features are enabled | +| ↳ `allowWritebackCells` | boolean | Whether writeback cells are allowed | +| `total` | number | Total number of connections returned | + +### `hex_list_groups` + +List all groups in the Hex workspace with optional sorting. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `limit` | number | No | Maximum number of groups to return \(1-500, default: 25\) | +| `sortBy` | string | No | Sort by field: CREATED_AT or NAME | +| `sortDirection` | string | No | Sort direction: ASC or DESC | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `groups` | array | List of workspace groups | +| ↳ `id` | string | Group UUID | +| ↳ `name` | string | Group name | +| ↳ `createdAt` | string | Creation timestamp | +| `total` | number | Total number of groups returned | + +### `hex_list_projects` + +List all projects in your Hex workspace with optional filtering by status. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `limit` | number | No | Maximum number of projects to return \(1-100\) | +| `includeArchived` | boolean | No | Include archived projects in results | +| `statusFilter` | string | No | Filter by status: PUBLISHED, DRAFT, or ALL | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `projects` | array | List of Hex projects | +| ↳ `id` | string | Project UUID | +| ↳ `title` | string | Project title | +| ↳ `description` | string | Project description | +| ↳ `status` | object | Project status | +| ↳ `name` | string | Status name \(e.g., PUBLISHED, DRAFT\) | +| ↳ `type` | string | Project type \(PROJECT or COMPONENT\) | +| ↳ `creator` | object | Project creator | +| ↳ `email` | string | Creator email | +| ↳ `owner` | object | Project owner | +| ↳ `email` | string | Owner email | +| ↳ `lastEditedAt` | string | Last edited timestamp | +| ↳ `lastPublishedAt` | string | Last published timestamp | +| ↳ `createdAt` | string | Creation timestamp | +| ↳ `archivedAt` | string | Archived timestamp | +| `total` | number | Total number of projects returned | + +### `hex_list_users` + +List all users in the Hex workspace with optional filtering and sorting. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `limit` | number | No | Maximum number of users to return \(1-100, default: 25\) | +| `sortBy` | string | No | Sort by field: NAME or EMAIL | +| `sortDirection` | string | No | Sort direction: ASC or DESC | +| `groupId` | string | No | Filter users by group UUID | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `users` | array | List of workspace users | +| ↳ `id` | string | User UUID | +| ↳ `name` | string | User name | +| ↳ `email` | string | User email | +| ↳ `role` | string | User role \(ADMIN, MANAGER, EDITOR, EXPLORER, MEMBER, GUEST, EMBEDDED_USER, ANONYMOUS\) | +| `total` | number | Total number of users returned | + +### `hex_run_project` + +Execute a published Hex project. Optionally pass input parameters and control caching behavior. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project to run | +| `inputParams` | json | No | JSON object of input parameters for the project \(e.g., \{"date": "2024-01-01"\}\) | +| `dryRun` | boolean | No | If true, perform a dry run without executing the project | +| `updateCache` | boolean | No | \(Deprecated\) If true, update the cached results after execution | +| `updatePublishedResults` | boolean | No | If true, update the published app results after execution | +| `useCachedSqlResults` | boolean | No | If true, use cached SQL results instead of re-running queries | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `projectId` | string | Project UUID | +| `runId` | string | Run UUID | +| `runUrl` | string | URL to view the run | +| `runStatusUrl` | string | URL to check run status | +| `traceId` | string | Trace ID for debugging | +| `projectVersion` | number | Project version number | + +### `hex_update_project` + +Update a Hex project status label (e.g., endorsement or custom workspace statuses). + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Hex API token \(Personal or Workspace\) | +| `projectId` | string | Yes | The UUID of the Hex project to update | +| `status` | string | Yes | New project status name \(custom workspace status label\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `id` | string | Project UUID | +| `title` | string | Project title | +| `description` | string | Project description | +| `status` | object | Updated project status | +| ↳ `name` | string | Status name \(e.g., PUBLISHED, DRAFT\) | +| `type` | string | Project type \(PROJECT or COMPONENT\) | +| `creator` | object | Project creator | +| ↳ `email` | string | Creator email | +| `owner` | object | Project owner | +| ↳ `email` | string | Owner email | +| `categories` | array | Project categories | +| ↳ `name` | string | Category name | +| ↳ `description` | string | Category description | +| `lastEditedAt` | string | Last edited timestamp | +| `lastPublishedAt` | string | Last published timestamp | +| `createdAt` | string | Creation timestamp | +| `archivedAt` | string | Archived timestamp | +| `trashedAt` | string | Trashed timestamp | + + diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 58317bea9f..3a3a1cc16d 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -49,6 +49,7 @@ "grafana", "grain", "greptile", + "hex", "hubspot", "huggingface", "hunter", diff --git a/apps/sim/blocks/blocks/hex.ts b/apps/sim/blocks/blocks/hex.ts new file mode 100644 index 0000000000..8e11c8ff29 --- /dev/null +++ b/apps/sim/blocks/blocks/hex.ts @@ -0,0 +1,440 @@ +import { HexIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' +import type { HexResponse } from '@/tools/hex/types' + +export const HexBlock: BlockConfig = { + type: 'hex', + name: 'Hex', + description: 'Run and manage Hex projects', + longDescription: + 'Integrate Hex into your workflow. Run projects, check run status, manage collections and groups, list users, and view data connections. Requires a Hex API token.', + docsLink: 'https://docs.sim.ai/tools/hex', + category: 'tools', + bgColor: '#F5E6FF', + icon: HexIcon, + authMode: AuthMode.ApiKey, + + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Run Project', id: 'run_project' }, + { label: 'Get Run Status', id: 'get_run_status' }, + { label: 'Get Project Runs', id: 'get_project_runs' }, + { label: 'Cancel Run', id: 'cancel_run' }, + { label: 'List Projects', id: 'list_projects' }, + { label: 'Get Project', id: 'get_project' }, + { label: 'Update Project', id: 'update_project' }, + { label: 'Get Queried Tables', id: 'get_queried_tables' }, + { label: 'List Users', id: 'list_users' }, + { label: 'List Groups', id: 'list_groups' }, + { label: 'Get Group', id: 'get_group' }, + { label: 'List Collections', id: 'list_collections' }, + { label: 'Get Collection', id: 'get_collection' }, + { label: 'Create Collection', id: 'create_collection' }, + { label: 'List Data Connections', id: 'list_data_connections' }, + { label: 'Get Data Connection', id: 'get_data_connection' }, + ], + value: () => 'run_project', + }, + { + id: 'projectId', + title: 'Project ID', + type: 'short-input', + placeholder: 'Enter project UUID', + condition: { + field: 'operation', + value: [ + 'run_project', + 'get_run_status', + 'get_project_runs', + 'cancel_run', + 'get_project', + 'update_project', + 'get_queried_tables', + ], + }, + required: { + field: 'operation', + value: [ + 'run_project', + 'get_run_status', + 'get_project_runs', + 'cancel_run', + 'get_project', + 'update_project', + 'get_queried_tables', + ], + }, + }, + { + id: 'runId', + title: 'Run ID', + type: 'short-input', + placeholder: 'Enter run UUID', + condition: { field: 'operation', value: ['get_run_status', 'cancel_run'] }, + required: { field: 'operation', value: ['get_run_status', 'cancel_run'] }, + }, + { + id: 'inputParams', + title: 'Input Parameters', + type: 'code', + placeholder: '{"param_name": "value"}', + condition: { field: 'operation', value: 'run_project' }, + wandConfig: { + enabled: true, + maintainHistory: true, + prompt: `You are an expert at creating Hex project input parameters. +Generate ONLY the raw JSON object based on the user's request. +The output MUST be a single, valid JSON object, starting with { and ending with }. + +Current parameters: {context} + +Do not include any explanations, markdown formatting, or other text outside the JSON object. +The keys should match the input parameter names defined in the Hex project. + +Example: +{ + "date_range": "2024-01-01", + "department": "engineering", + "include_inactive": false +}`, + placeholder: 'Describe the input parameters you need...', + generationType: 'json-object', + }, + }, + { + id: 'projectStatus', + title: 'Status', + type: 'short-input', + placeholder: 'Enter status name (e.g., custom workspace status label)', + condition: { field: 'operation', value: 'update_project' }, + required: { field: 'operation', value: 'update_project' }, + }, + { + id: 'runStatusFilter', + title: 'Status Filter', + type: 'dropdown', + options: [ + { label: 'All', id: '' }, + { label: 'Pending', id: 'PENDING' }, + { label: 'Running', id: 'RUNNING' }, + { label: 'Completed', id: 'COMPLETED' }, + { label: 'Errored', id: 'ERRORED' }, + { label: 'Killed', id: 'KILLED' }, + ], + value: () => '', + condition: { field: 'operation', value: 'get_project_runs' }, + }, + { + id: 'groupIdInput', + title: 'Group ID', + type: 'short-input', + placeholder: 'Enter group UUID', + condition: { field: 'operation', value: 'get_group' }, + required: { field: 'operation', value: 'get_group' }, + }, + { + id: 'collectionId', + title: 'Collection ID', + type: 'short-input', + placeholder: 'Enter collection UUID', + condition: { field: 'operation', value: 'get_collection' }, + required: { field: 'operation', value: 'get_collection' }, + }, + { + id: 'collectionName', + title: 'Collection Name', + type: 'short-input', + placeholder: 'Enter collection name', + condition: { field: 'operation', value: 'create_collection' }, + required: { field: 'operation', value: 'create_collection' }, + }, + { + id: 'collectionDescription', + title: 'Description', + type: 'long-input', + placeholder: 'Optional description for the collection', + condition: { field: 'operation', value: 'create_collection' }, + }, + { + id: 'dataConnectionId', + title: 'Data Connection ID', + type: 'short-input', + placeholder: 'Enter data connection UUID', + condition: { field: 'operation', value: 'get_data_connection' }, + required: { field: 'operation', value: 'get_data_connection' }, + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + placeholder: 'Enter your Hex API token', + password: true, + required: true, + }, + // Advanced fields + { + id: 'dryRun', + title: 'Dry Run', + type: 'switch', + condition: { field: 'operation', value: 'run_project' }, + mode: 'advanced', + }, + { + id: 'updateCache', + title: 'Update Cache', + type: 'switch', + condition: { field: 'operation', value: 'run_project' }, + mode: 'advanced', + }, + { + id: 'updatePublishedResults', + title: 'Update Published Results', + type: 'switch', + condition: { field: 'operation', value: 'run_project' }, + mode: 'advanced', + }, + { + id: 'useCachedSqlResults', + title: 'Use Cached SQL Results', + type: 'switch', + condition: { field: 'operation', value: 'run_project' }, + mode: 'advanced', + }, + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: '25', + condition: { + field: 'operation', + value: [ + 'list_projects', + 'get_project_runs', + 'get_queried_tables', + 'list_users', + 'list_groups', + 'list_collections', + 'list_data_connections', + ], + }, + mode: 'advanced', + }, + { + id: 'offset', + title: 'Offset', + type: 'short-input', + placeholder: '0', + condition: { field: 'operation', value: 'get_project_runs' }, + mode: 'advanced', + }, + { + id: 'includeArchived', + title: 'Include Archived', + type: 'switch', + condition: { field: 'operation', value: 'list_projects' }, + mode: 'advanced', + }, + { + id: 'statusFilter', + title: 'Status Filter', + type: 'dropdown', + options: [ + { label: 'All', id: '' }, + { label: 'Published', id: 'PUBLISHED' }, + { label: 'Draft', id: 'DRAFT' }, + ], + value: () => '', + condition: { field: 'operation', value: 'list_projects' }, + mode: 'advanced', + }, + { + id: 'groupId', + title: 'Filter by Group', + type: 'short-input', + placeholder: 'Group UUID (optional)', + condition: { field: 'operation', value: 'list_users' }, + mode: 'advanced', + }, + ], + + tools: { + access: [ + 'hex_cancel_run', + 'hex_create_collection', + 'hex_get_collection', + 'hex_get_data_connection', + 'hex_get_group', + 'hex_get_project', + 'hex_get_project_runs', + 'hex_get_queried_tables', + 'hex_get_run_status', + 'hex_list_collections', + 'hex_list_data_connections', + 'hex_list_groups', + 'hex_list_projects', + 'hex_list_users', + 'hex_run_project', + 'hex_update_project', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'run_project': + return 'hex_run_project' + case 'get_run_status': + return 'hex_get_run_status' + case 'get_project_runs': + return 'hex_get_project_runs' + case 'cancel_run': + return 'hex_cancel_run' + case 'list_projects': + return 'hex_list_projects' + case 'get_project': + return 'hex_get_project' + case 'update_project': + return 'hex_update_project' + case 'get_queried_tables': + return 'hex_get_queried_tables' + case 'list_users': + return 'hex_list_users' + case 'list_groups': + return 'hex_list_groups' + case 'get_group': + return 'hex_get_group' + case 'list_collections': + return 'hex_list_collections' + case 'get_collection': + return 'hex_get_collection' + case 'create_collection': + return 'hex_create_collection' + case 'list_data_connections': + return 'hex_list_data_connections' + case 'get_data_connection': + return 'hex_get_data_connection' + default: + return 'hex_run_project' + } + }, + params: (params) => { + const result: Record = {} + if (params.limit) result.limit = Number(params.limit) + if (params.offset) result.offset = Number(params.offset) + if (params.projectStatus) result.status = params.projectStatus + if (params.runStatusFilter) result.statusFilter = params.runStatusFilter + if (params.groupIdInput) result.groupId = params.groupIdInput + if (params.collectionName) result.name = params.collectionName + if (params.collectionDescription) result.description = params.collectionDescription + return result + }, + }, + }, + + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + apiKey: { type: 'string', description: 'Hex API token' }, + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID' }, + inputParams: { type: 'json', description: 'Input parameters for project run' }, + dryRun: { type: 'boolean', description: 'Perform a dry run without executing the project' }, + updateCache: { + type: 'boolean', + description: '(Deprecated) Update cached results after execution', + }, + updatePublishedResults: { + type: 'boolean', + description: 'Update published app results after execution', + }, + useCachedSqlResults: { + type: 'boolean', + description: 'Use cached SQL results instead of re-running queries', + }, + projectStatus: { + type: 'string', + description: 'New project status name (custom workspace status label)', + }, + limit: { type: 'number', description: 'Max number of results to return' }, + offset: { type: 'number', description: 'Offset for paginated results' }, + includeArchived: { type: 'boolean', description: 'Include archived projects' }, + statusFilter: { type: 'string', description: 'Filter projects by status' }, + runStatusFilter: { type: 'string', description: 'Filter runs by status' }, + groupId: { type: 'string', description: 'Filter users by group UUID' }, + groupIdInput: { type: 'string', description: 'Group UUID for get group' }, + collectionId: { type: 'string', description: 'Collection UUID' }, + collectionName: { type: 'string', description: 'Collection name' }, + collectionDescription: { type: 'string', description: 'Collection description' }, + dataConnectionId: { type: 'string', description: 'Data connection UUID' }, + }, + + outputs: { + // Run creation outputs + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID' }, + runUrl: { type: 'string', description: 'URL to view the run' }, + runStatusUrl: { type: 'string', description: 'URL to check run status' }, + projectVersion: { type: 'number', description: 'Project version number' }, + // Run status outputs + status: { + type: 'json', + description: 'Project status object ({ name }) or run status string', + }, + startTime: { type: 'string', description: 'Run start time' }, + endTime: { type: 'string', description: 'Run end time' }, + elapsedTime: { type: 'number', description: 'Elapsed time in seconds' }, + traceId: { type: 'string', description: 'Trace ID for debugging' }, + // Project outputs + id: { type: 'string', description: 'Resource ID' }, + title: { type: 'string', description: 'Project title' }, + name: { type: 'string', description: 'Resource name' }, + description: { type: 'string', description: 'Resource description' }, + type: { type: 'string', description: 'Project type (PROJECT or COMPONENT)' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + updatedAt: { type: 'string', description: 'Last update timestamp' }, + lastEditedAt: { type: 'string', description: 'Last edited timestamp' }, + lastPublishedAt: { type: 'string', description: 'Last published timestamp' }, + archivedAt: { type: 'string', description: 'Archived timestamp' }, + trashedAt: { type: 'string', description: 'Trashed timestamp' }, + // List outputs + projects: { + type: 'json', + description: 'List of projects with id, title, status, type, creator, owner, createdAt', + }, + runs: { + type: 'json', + description: + 'List of runs with runId, status, runUrl, startTime, endTime, elapsedTime, projectVersion', + }, + users: { type: 'json', description: 'List of users with id, name, email, role' }, + groups: { type: 'json', description: 'List of groups with id, name, createdAt' }, + collections: { + type: 'json', + description: 'List of collections with id, name, description, creator', + }, + connections: { + type: 'json', + description: + 'List of data connections with id, name, type, description, connectViaSsh, includeMagic, allowWritebackCells', + }, + tables: { + type: 'json', + description: 'List of queried tables with dataConnectionId, dataConnectionName, tableName', + }, + categories: { + type: 'json', + description: 'Project categories with name and description', + }, + creator: { type: 'json', description: 'Creator details ({ email, id })' }, + owner: { type: 'json', description: 'Owner details ({ email })' }, + total: { type: 'number', description: 'Total results returned' }, + // Cancel output + success: { type: 'boolean', description: 'Whether the operation succeeded' }, + // Data connection flags + connectViaSsh: { type: 'boolean', description: 'SSH tunneling enabled' }, + includeMagic: { type: 'boolean', description: 'Magic AI features enabled' }, + allowWritebackCells: { type: 'boolean', description: 'Writeback cells allowed' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index c4851fe793..70b9e915bf 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -55,6 +55,7 @@ import { GrafanaBlock } from '@/blocks/blocks/grafana' import { GrainBlock } from '@/blocks/blocks/grain' import { GreptileBlock } from '@/blocks/blocks/greptile' import { GuardrailsBlock } from '@/blocks/blocks/guardrails' +import { HexBlock } from '@/blocks/blocks/hex' import { HubSpotBlock } from '@/blocks/blocks/hubspot' import { HuggingFaceBlock } from '@/blocks/blocks/huggingface' import { HumanInTheLoopBlock } from '@/blocks/blocks/human_in_the_loop' @@ -240,6 +241,7 @@ export const registry: Record = { grain: GrainBlock, greptile: GreptileBlock, guardrails: GuardrailsBlock, + hex: HexBlock, hubspot: HubSpotBlock, huggingface: HuggingFaceBlock, human_in_the_loop: HumanInTheLoopBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 16c248b74d..1d50d0d068 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -5819,3 +5819,15 @@ export function RedisIcon(props: SVGProps) { ) } + +export function HexIcon(props: SVGProps) { + return ( + + + + ) +} diff --git a/apps/sim/tools/hex/cancel_run.ts b/apps/sim/tools/hex/cancel_run.ts new file mode 100644 index 0000000000..17c65944c3 --- /dev/null +++ b/apps/sim/tools/hex/cancel_run.ts @@ -0,0 +1,70 @@ +import type { HexCancelRunParams, HexCancelRunResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const cancelRunTool: ToolConfig = { + id: 'hex_cancel_run', + name: 'Hex Cancel Run', + description: 'Cancel an active Hex project run.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project', + }, + runId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the run to cancel', + }, + }, + + request: { + url: (params) => + `https://app.hex.tech/api/v1/projects/${params.projectId}/runs/${params.runId}`, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response, params) => { + if (response.status === 204 || response.ok) { + return { + success: true, + output: { + success: true, + projectId: params?.projectId ?? '', + runId: params?.runId ?? '', + }, + } + } + + const data = await response.json().catch(() => ({})) + return { + success: false, + output: { + success: false, + projectId: params?.projectId ?? '', + runId: params?.runId ?? '', + }, + error: (data as Record).message ?? 'Failed to cancel run', + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether the run was successfully cancelled' }, + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID that was cancelled' }, + }, +} diff --git a/apps/sim/tools/hex/create_collection.ts b/apps/sim/tools/hex/create_collection.ts new file mode 100644 index 0000000000..4a61e08bc2 --- /dev/null +++ b/apps/sim/tools/hex/create_collection.ts @@ -0,0 +1,78 @@ +import type { HexCreateCollectionParams, HexCreateCollectionResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const createCollectionTool: ToolConfig< + HexCreateCollectionParams, + HexCreateCollectionResponse +> = { + id: 'hex_create_collection', + name: 'Hex Create Collection', + description: 'Create a new collection in the Hex workspace to organize projects.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + name: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Name for the new collection', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Optional description for the collection', + }, + }, + + request: { + url: 'https://app.hex.tech/api/v1/collections', + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = { name: params.name } + if (params.description) body.description = params.description + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + name: data.name ?? null, + description: data.description ?? null, + creator: data.creator + ? { email: data.creator.email ?? null, id: data.creator.id ?? null } + : null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Newly created collection UUID' }, + name: { type: 'string', description: 'Collection name' }, + description: { type: 'string', description: 'Collection description', optional: true }, + creator: { + type: 'object', + description: 'Collection creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + id: { type: 'string', description: 'Creator UUID' }, + }, + }, + }, +} diff --git a/apps/sim/tools/hex/get_collection.ts b/apps/sim/tools/hex/get_collection.ts new file mode 100644 index 0000000000..8222d88a92 --- /dev/null +++ b/apps/sim/tools/hex/get_collection.ts @@ -0,0 +1,64 @@ +import type { HexGetCollectionParams, HexGetCollectionResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getCollectionTool: ToolConfig = { + id: 'hex_get_collection', + name: 'Hex Get Collection', + description: 'Retrieve details for a specific Hex collection by its ID.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + collectionId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the collection', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + name: data.name ?? null, + description: data.description ?? null, + creator: data.creator + ? { email: data.creator.email ?? null, id: data.creator.id ?? null } + : null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Collection UUID' }, + name: { type: 'string', description: 'Collection name' }, + description: { type: 'string', description: 'Collection description', optional: true }, + creator: { + type: 'object', + description: 'Collection creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + id: { type: 'string', description: 'Creator UUID' }, + }, + }, + }, +} diff --git a/apps/sim/tools/hex/get_data_connection.ts b/apps/sim/tools/hex/get_data_connection.ts new file mode 100644 index 0000000000..3b9e54b94f --- /dev/null +++ b/apps/sim/tools/hex/get_data_connection.ts @@ -0,0 +1,76 @@ +import type { HexGetDataConnectionParams, HexGetDataConnectionResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getDataConnectionTool: ToolConfig< + HexGetDataConnectionParams, + HexGetDataConnectionResponse +> = { + id: 'hex_get_data_connection', + name: 'Hex Get Data Connection', + description: + 'Retrieve details for a specific data connection including type, description, and configuration flags.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + dataConnectionId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the data connection', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/data-connections/${params.dataConnectionId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + name: data.name ?? null, + type: data.type ?? null, + description: data.description ?? null, + connectViaSsh: data.connectViaSsh ?? null, + includeMagic: data.includeMagic ?? null, + allowWritebackCells: data.allowWritebackCells ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Connection UUID' }, + name: { type: 'string', description: 'Connection name' }, + type: { type: 'string', description: 'Connection type (e.g., snowflake, postgres, bigquery)' }, + description: { type: 'string', description: 'Connection description', optional: true }, + connectViaSsh: { + type: 'boolean', + description: 'Whether SSH tunneling is enabled', + optional: true, + }, + includeMagic: { + type: 'boolean', + description: 'Whether Magic AI features are enabled', + optional: true, + }, + allowWritebackCells: { + type: 'boolean', + description: 'Whether writeback cells are allowed', + optional: true, + }, + }, +} diff --git a/apps/sim/tools/hex/get_group.ts b/apps/sim/tools/hex/get_group.ts new file mode 100644 index 0000000000..c649e657a8 --- /dev/null +++ b/apps/sim/tools/hex/get_group.ts @@ -0,0 +1,52 @@ +import type { HexGetGroupParams, HexGetGroupResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getGroupTool: ToolConfig = { + id: 'hex_get_group', + name: 'Hex Get Group', + description: 'Retrieve details for a specific Hex group.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + groupId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the group', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + name: data.name ?? null, + createdAt: data.createdAt ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Group UUID' }, + name: { type: 'string', description: 'Group name' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + }, +} diff --git a/apps/sim/tools/hex/get_project.ts b/apps/sim/tools/hex/get_project.ts new file mode 100644 index 0000000000..fda718f2f6 --- /dev/null +++ b/apps/sim/tools/hex/get_project.ts @@ -0,0 +1,78 @@ +import type { HexGetProjectParams, HexGetProjectResponse } from '@/tools/hex/types' +import { HEX_PROJECT_OUTPUT_PROPERTIES } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getProjectTool: ToolConfig = { + id: 'hex_get_project', + name: 'Hex Get Project', + description: 'Get metadata and details for a specific Hex project by its ID.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + title: data.title ?? null, + description: data.description ?? null, + status: data.status ? { name: data.status.name ?? null } : null, + type: data.type ?? null, + creator: data.creator ? { email: data.creator.email ?? null } : null, + owner: data.owner ? { email: data.owner.email ?? null } : null, + categories: Array.isArray(data.categories) + ? data.categories.map((c: Record) => ({ + name: c.name ?? null, + description: c.description ?? null, + })) + : [], + lastEditedAt: data.lastEditedAt ?? null, + lastPublishedAt: data.lastPublishedAt ?? null, + createdAt: data.createdAt ?? null, + archivedAt: data.archivedAt ?? null, + trashedAt: data.trashedAt ?? null, + }, + } + }, + + outputs: { + id: HEX_PROJECT_OUTPUT_PROPERTIES.id, + title: HEX_PROJECT_OUTPUT_PROPERTIES.title, + description: HEX_PROJECT_OUTPUT_PROPERTIES.description, + status: HEX_PROJECT_OUTPUT_PROPERTIES.status, + type: HEX_PROJECT_OUTPUT_PROPERTIES.type, + creator: HEX_PROJECT_OUTPUT_PROPERTIES.creator, + owner: HEX_PROJECT_OUTPUT_PROPERTIES.owner, + categories: HEX_PROJECT_OUTPUT_PROPERTIES.categories, + lastEditedAt: HEX_PROJECT_OUTPUT_PROPERTIES.lastEditedAt, + lastPublishedAt: HEX_PROJECT_OUTPUT_PROPERTIES.lastPublishedAt, + createdAt: HEX_PROJECT_OUTPUT_PROPERTIES.createdAt, + archivedAt: HEX_PROJECT_OUTPUT_PROPERTIES.archivedAt, + trashedAt: HEX_PROJECT_OUTPUT_PROPERTIES.trashedAt, + }, +} diff --git a/apps/sim/tools/hex/get_project_runs.ts b/apps/sim/tools/hex/get_project_runs.ts new file mode 100644 index 0000000000..9d2897d900 --- /dev/null +++ b/apps/sim/tools/hex/get_project_runs.ts @@ -0,0 +1,115 @@ +import type { HexGetProjectRunsParams, HexGetProjectRunsResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getProjectRunsTool: ToolConfig = { + id: 'hex_get_project_runs', + name: 'Hex Get Project Runs', + description: + 'Retrieve API-triggered runs for a Hex project with optional filtering by status and pagination.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of runs to return (1-100, default: 25)', + }, + offset: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Offset for paginated results (default: 0)', + }, + statusFilter: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Filter by run status: PENDING, RUNNING, ERRORED, COMPLETED, KILLED, UNABLE_TO_ALLOCATE_KERNEL', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.offset) searchParams.set('offset', String(params.offset)) + if (params.statusFilter) searchParams.set('statusFilter', params.statusFilter) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/projects/${params.projectId}/runs${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const runs = Array.isArray(data) ? data : (data.runs ?? []) + + return { + success: true, + output: { + runs: runs.map((r: Record) => ({ + projectId: (r.projectId as string) ?? null, + runId: (r.runId as string) ?? null, + runUrl: (r.runUrl as string) ?? null, + status: (r.status as string) ?? null, + startTime: (r.startTime as string) ?? null, + endTime: (r.endTime as string) ?? null, + elapsedTime: (r.elapsedTime as number) ?? null, + traceId: (r.traceId as string) ?? null, + projectVersion: (r.projectVersion as number) ?? null, + })), + total: runs.length, + traceId: data.traceId ?? null, + }, + } + }, + + outputs: { + runs: { + type: 'array', + description: 'List of project runs', + items: { + type: 'object', + properties: { + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID' }, + runUrl: { type: 'string', description: 'URL to view the run', optional: true }, + status: { + type: 'string', + description: + 'Run status (PENDING, RUNNING, COMPLETED, ERRORED, KILLED, UNABLE_TO_ALLOCATE_KERNEL)', + }, + startTime: { type: 'string', description: 'Run start time', optional: true }, + endTime: { type: 'string', description: 'Run end time', optional: true }, + elapsedTime: { type: 'number', description: 'Elapsed time in seconds', optional: true }, + traceId: { type: 'string', description: 'Trace ID', optional: true }, + projectVersion: { + type: 'number', + description: 'Project version number', + optional: true, + }, + }, + }, + }, + total: { type: 'number', description: 'Total number of runs returned' }, + traceId: { type: 'string', description: 'Top-level trace ID', optional: true }, + }, +} diff --git a/apps/sim/tools/hex/get_queried_tables.ts b/apps/sim/tools/hex/get_queried_tables.ts new file mode 100644 index 0000000000..2261cd3c27 --- /dev/null +++ b/apps/sim/tools/hex/get_queried_tables.ts @@ -0,0 +1,81 @@ +import type { HexGetQueriedTablesParams, HexGetQueriedTablesResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getQueriedTablesTool: ToolConfig< + HexGetQueriedTablesParams, + HexGetQueriedTablesResponse +> = { + id: 'hex_get_queried_tables', + name: 'Hex Get Queried Tables', + description: + 'Return the warehouse tables queried by a Hex project, including data connection and table names.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of tables to return (1-100)', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/projects/${params.projectId}/queriedTables${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const tables = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + tables: tables.map((t: Record) => ({ + dataConnectionId: (t.dataConnectionId as string) ?? null, + dataConnectionName: (t.dataConnectionName as string) ?? null, + tableName: (t.tableName as string) ?? null, + })), + total: tables.length, + }, + } + }, + + outputs: { + tables: { + type: 'array', + description: 'List of warehouse tables queried by the project', + items: { + type: 'object', + properties: { + dataConnectionId: { type: 'string', description: 'Data connection UUID' }, + dataConnectionName: { type: 'string', description: 'Data connection name' }, + tableName: { type: 'string', description: 'Table name' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of tables returned' }, + }, +} diff --git a/apps/sim/tools/hex/get_run_status.ts b/apps/sim/tools/hex/get_run_status.ts new file mode 100644 index 0000000000..90dd26cdb0 --- /dev/null +++ b/apps/sim/tools/hex/get_run_status.ts @@ -0,0 +1,72 @@ +import type { HexGetRunStatusParams, HexGetRunStatusResponse } from '@/tools/hex/types' +import { HEX_RUN_STATUS_OUTPUT_PROPERTIES } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const getRunStatusTool: ToolConfig = { + id: 'hex_get_run_status', + name: 'Hex Get Run Status', + description: 'Check the status of a Hex project run by its run ID.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project', + }, + runId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the run to check', + }, + }, + + request: { + url: (params) => + `https://app.hex.tech/api/v1/projects/${params.projectId}/runs/${params.runId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + projectId: data.projectId ?? null, + runId: data.runId ?? null, + runUrl: data.runUrl ?? null, + status: data.status ?? null, + startTime: data.startTime ?? null, + endTime: data.endTime ?? null, + elapsedTime: data.elapsedTime ?? null, + traceId: data.traceId ?? null, + projectVersion: data.projectVersion ?? null, + }, + } + }, + + outputs: { + projectId: HEX_RUN_STATUS_OUTPUT_PROPERTIES.projectId, + runId: HEX_RUN_STATUS_OUTPUT_PROPERTIES.runId, + runUrl: HEX_RUN_STATUS_OUTPUT_PROPERTIES.runUrl, + status: HEX_RUN_STATUS_OUTPUT_PROPERTIES.status, + startTime: HEX_RUN_STATUS_OUTPUT_PROPERTIES.startTime, + endTime: HEX_RUN_STATUS_OUTPUT_PROPERTIES.endTime, + elapsedTime: HEX_RUN_STATUS_OUTPUT_PROPERTIES.elapsedTime, + traceId: HEX_RUN_STATUS_OUTPUT_PROPERTIES.traceId, + projectVersion: HEX_RUN_STATUS_OUTPUT_PROPERTIES.projectVersion, + }, +} diff --git a/apps/sim/tools/hex/index.ts b/apps/sim/tools/hex/index.ts new file mode 100644 index 0000000000..9a561587d7 --- /dev/null +++ b/apps/sim/tools/hex/index.ts @@ -0,0 +1,33 @@ +import { cancelRunTool } from '@/tools/hex/cancel_run' +import { createCollectionTool } from '@/tools/hex/create_collection' +import { getCollectionTool } from '@/tools/hex/get_collection' +import { getDataConnectionTool } from '@/tools/hex/get_data_connection' +import { getGroupTool } from '@/tools/hex/get_group' +import { getProjectTool } from '@/tools/hex/get_project' +import { getProjectRunsTool } from '@/tools/hex/get_project_runs' +import { getQueriedTablesTool } from '@/tools/hex/get_queried_tables' +import { getRunStatusTool } from '@/tools/hex/get_run_status' +import { listCollectionsTool } from '@/tools/hex/list_collections' +import { listDataConnectionsTool } from '@/tools/hex/list_data_connections' +import { listGroupsTool } from '@/tools/hex/list_groups' +import { listProjectsTool } from '@/tools/hex/list_projects' +import { listUsersTool } from '@/tools/hex/list_users' +import { runProjectTool } from '@/tools/hex/run_project' +import { updateProjectTool } from '@/tools/hex/update_project' + +export const hexCancelRunTool = cancelRunTool +export const hexCreateCollectionTool = createCollectionTool +export const hexGetCollectionTool = getCollectionTool +export const hexGetDataConnectionTool = getDataConnectionTool +export const hexGetGroupTool = getGroupTool +export const hexGetProjectTool = getProjectTool +export const hexGetProjectRunsTool = getProjectRunsTool +export const hexGetQueriedTablesTool = getQueriedTablesTool +export const hexGetRunStatusTool = getRunStatusTool +export const hexListCollectionsTool = listCollectionsTool +export const hexListDataConnectionsTool = listDataConnectionsTool +export const hexListGroupsTool = listGroupsTool +export const hexListProjectsTool = listProjectsTool +export const hexListUsersTool = listUsersTool +export const hexRunProjectTool = runProjectTool +export const hexUpdateProjectTool = updateProjectTool diff --git a/apps/sim/tools/hex/list_collections.ts b/apps/sim/tools/hex/list_collections.ts new file mode 100644 index 0000000000..9902db0d15 --- /dev/null +++ b/apps/sim/tools/hex/list_collections.ts @@ -0,0 +1,94 @@ +import type { HexListCollectionsParams, HexListCollectionsResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const listCollectionsTool: ToolConfig = + { + id: 'hex_list_collections', + name: 'Hex List Collections', + description: 'List all collections in the Hex workspace.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of collections to return (1-500, default: 25)', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort by field: NAME', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.sortBy) searchParams.set('sortBy', params.sortBy) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/collections${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const collections = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + collections: collections.map((c: Record) => ({ + id: (c.id as string) ?? null, + name: (c.name as string) ?? null, + description: (c.description as string) ?? null, + creator: c.creator + ? { + email: (c.creator as Record).email ?? null, + id: (c.creator as Record).id ?? null, + } + : null, + })), + total: collections.length, + }, + } + }, + + outputs: { + collections: { + type: 'array', + description: 'List of collections', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Collection UUID' }, + name: { type: 'string', description: 'Collection name' }, + description: { type: 'string', description: 'Collection description', optional: true }, + creator: { + type: 'object', + description: 'Collection creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + id: { type: 'string', description: 'Creator UUID' }, + }, + }, + }, + }, + }, + total: { type: 'number', description: 'Total number of collections returned' }, + }, + } diff --git a/apps/sim/tools/hex/list_data_connections.ts b/apps/sim/tools/hex/list_data_connections.ts new file mode 100644 index 0000000000..24dc97cae0 --- /dev/null +++ b/apps/sim/tools/hex/list_data_connections.ts @@ -0,0 +1,116 @@ +import type { + HexListDataConnectionsParams, + HexListDataConnectionsResponse, +} from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const listDataConnectionsTool: ToolConfig< + HexListDataConnectionsParams, + HexListDataConnectionsResponse +> = { + id: 'hex_list_data_connections', + name: 'Hex List Data Connections', + description: + 'List all data connections in the Hex workspace (e.g., Snowflake, PostgreSQL, BigQuery).', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of connections to return (1-500, default: 25)', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort by field: CREATED_AT or NAME', + }, + sortDirection: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort direction: ASC or DESC', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.sortBy) searchParams.set('sortBy', params.sortBy) + if (params.sortDirection) searchParams.set('sortDirection', params.sortDirection) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/data-connections${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const connections = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + connections: connections.map((c: Record) => ({ + id: (c.id as string) ?? null, + name: (c.name as string) ?? null, + type: (c.type as string) ?? null, + description: (c.description as string) ?? null, + connectViaSsh: (c.connectViaSsh as boolean) ?? null, + includeMagic: (c.includeMagic as boolean) ?? null, + allowWritebackCells: (c.allowWritebackCells as boolean) ?? null, + })), + total: connections.length, + }, + } + }, + + outputs: { + connections: { + type: 'array', + description: 'List of data connections', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Connection UUID' }, + name: { type: 'string', description: 'Connection name' }, + type: { + type: 'string', + description: + 'Connection type (e.g., athena, bigquery, databricks, postgres, redshift, snowflake)', + }, + description: { type: 'string', description: 'Connection description', optional: true }, + connectViaSsh: { + type: 'boolean', + description: 'Whether SSH tunneling is enabled', + optional: true, + }, + includeMagic: { + type: 'boolean', + description: 'Whether Magic AI features are enabled', + optional: true, + }, + allowWritebackCells: { + type: 'boolean', + description: 'Whether writeback cells are allowed', + optional: true, + }, + }, + }, + }, + total: { type: 'number', description: 'Total number of connections returned' }, + }, +} diff --git a/apps/sim/tools/hex/list_groups.ts b/apps/sim/tools/hex/list_groups.ts new file mode 100644 index 0000000000..c74cebe91f --- /dev/null +++ b/apps/sim/tools/hex/list_groups.ts @@ -0,0 +1,85 @@ +import type { HexListGroupsParams, HexListGroupsResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const listGroupsTool: ToolConfig = { + id: 'hex_list_groups', + name: 'Hex List Groups', + description: 'List all groups in the Hex workspace with optional sorting.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of groups to return (1-500, default: 25)', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort by field: CREATED_AT or NAME', + }, + sortDirection: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort direction: ASC or DESC', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.sortBy) searchParams.set('sortBy', params.sortBy) + if (params.sortDirection) searchParams.set('sortDirection', params.sortDirection) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/groups${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const groups = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + groups: groups.map((g: Record) => ({ + id: (g.id as string) ?? null, + name: (g.name as string) ?? null, + createdAt: (g.createdAt as string) ?? null, + })), + total: groups.length, + }, + } + }, + + outputs: { + groups: { + type: 'array', + description: 'List of workspace groups', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Group UUID' }, + name: { type: 'string', description: 'Group name' }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + }, + }, + }, + total: { type: 'number', description: 'Total number of groups returned' }, + }, +} diff --git a/apps/sim/tools/hex/list_projects.ts b/apps/sim/tools/hex/list_projects.ts new file mode 100644 index 0000000000..502f954abc --- /dev/null +++ b/apps/sim/tools/hex/list_projects.ts @@ -0,0 +1,138 @@ +import type { HexListProjectsParams, HexListProjectsResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const listProjectsTool: ToolConfig = { + id: 'hex_list_projects', + name: 'Hex List Projects', + description: 'List all projects in your Hex workspace with optional filtering by status.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of projects to return (1-100)', + }, + includeArchived: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Include archived projects in results', + }, + statusFilter: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter by status: PUBLISHED, DRAFT, or ALL', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.includeArchived) searchParams.set('includeArchived', 'true') + if (params.statusFilter) searchParams.append('statuses[]', params.statusFilter) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/projects${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const projects = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + projects: projects.map((p: Record) => ({ + id: (p.id as string) ?? null, + title: (p.title as string) ?? null, + description: (p.description as string) ?? null, + status: p.status ? { name: (p.status as Record).name ?? null } : null, + type: (p.type as string) ?? null, + creator: p.creator + ? { email: (p.creator as Record).email ?? null } + : null, + owner: p.owner ? { email: (p.owner as Record).email ?? null } : null, + categories: Array.isArray(p.categories) + ? (p.categories as Array>).map((c) => ({ + name: c.name ?? null, + description: c.description ?? null, + })) + : [], + lastEditedAt: (p.lastEditedAt as string) ?? null, + lastPublishedAt: (p.lastPublishedAt as string) ?? null, + createdAt: (p.createdAt as string) ?? null, + archivedAt: (p.archivedAt as string) ?? null, + trashedAt: (p.trashedAt as string) ?? null, + })), + total: projects.length, + }, + } + }, + + outputs: { + projects: { + type: 'array', + description: 'List of Hex projects', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Project UUID' }, + title: { type: 'string', description: 'Project title' }, + description: { type: 'string', description: 'Project description', optional: true }, + status: { + type: 'object', + description: 'Project status', + properties: { + name: { type: 'string', description: 'Status name (e.g., PUBLISHED, DRAFT)' }, + }, + }, + type: { type: 'string', description: 'Project type (PROJECT or COMPONENT)' }, + creator: { + type: 'object', + description: 'Project creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + }, + }, + owner: { + type: 'object', + description: 'Project owner', + optional: true, + properties: { + email: { type: 'string', description: 'Owner email' }, + }, + }, + lastEditedAt: { + type: 'string', + description: 'Last edited timestamp', + optional: true, + }, + lastPublishedAt: { + type: 'string', + description: 'Last published timestamp', + optional: true, + }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + archivedAt: { type: 'string', description: 'Archived timestamp', optional: true }, + }, + }, + }, + total: { type: 'number', description: 'Total number of projects returned' }, + }, +} diff --git a/apps/sim/tools/hex/list_users.ts b/apps/sim/tools/hex/list_users.ts new file mode 100644 index 0000000000..f1ba9af6ad --- /dev/null +++ b/apps/sim/tools/hex/list_users.ts @@ -0,0 +1,98 @@ +import type { HexListUsersParams, HexListUsersResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const listUsersTool: ToolConfig = { + id: 'hex_list_users', + name: 'Hex List Users', + description: 'List all users in the Hex workspace with optional filtering and sorting.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of users to return (1-100, default: 25)', + }, + sortBy: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort by field: NAME or EMAIL', + }, + sortDirection: { + type: 'string', + required: false, + visibility: 'user-only', + description: 'Sort direction: ASC or DESC', + }, + groupId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Filter users by group UUID', + }, + }, + + request: { + url: (params) => { + const searchParams = new URLSearchParams() + if (params.limit) searchParams.set('limit', String(params.limit)) + if (params.sortBy) searchParams.set('sortBy', params.sortBy) + if (params.sortDirection) searchParams.set('sortDirection', params.sortDirection) + if (params.groupId) searchParams.set('groupId', params.groupId) + const qs = searchParams.toString() + return `https://app.hex.tech/api/v1/users${qs ? `?${qs}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const users = Array.isArray(data) ? data : (data.values ?? []) + + return { + success: true, + output: { + users: users.map((u: Record) => ({ + id: (u.id as string) ?? null, + name: (u.name as string) ?? null, + email: (u.email as string) ?? null, + role: (u.role as string) ?? null, + })), + total: users.length, + }, + } + }, + + outputs: { + users: { + type: 'array', + description: 'List of workspace users', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'User UUID' }, + name: { type: 'string', description: 'User name' }, + email: { type: 'string', description: 'User email' }, + role: { + type: 'string', + description: + 'User role (ADMIN, MANAGER, EDITOR, EXPLORER, MEMBER, GUEST, EMBEDDED_USER, ANONYMOUS)', + }, + }, + }, + }, + total: { type: 'number', description: 'Total number of users returned' }, + }, +} diff --git a/apps/sim/tools/hex/run_project.ts b/apps/sim/tools/hex/run_project.ts new file mode 100644 index 0000000000..3d11ac0346 --- /dev/null +++ b/apps/sim/tools/hex/run_project.ts @@ -0,0 +1,108 @@ +import type { HexRunProjectParams, HexRunProjectResponse } from '@/tools/hex/types' +import { HEX_RUN_OUTPUT_PROPERTIES } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const runProjectTool: ToolConfig = { + id: 'hex_run_project', + name: 'Hex Run Project', + description: + 'Execute a published Hex project. Optionally pass input parameters and control caching behavior.', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project to run', + }, + inputParams: { + type: 'json', + required: false, + visibility: 'user-or-llm', + description: 'JSON object of input parameters for the project (e.g., {"date": "2024-01-01"})', + }, + dryRun: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'If true, perform a dry run without executing the project', + }, + updateCache: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: '(Deprecated) If true, update the cached results after execution', + }, + updatePublishedResults: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'If true, update the published app results after execution', + }, + useCachedSqlResults: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'If true, use cached SQL results instead of re-running queries', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}/runs`, + method: 'POST', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => { + const body: Record = {} + + if (params.inputParams) { + body.inputParams = + typeof params.inputParams === 'string' + ? JSON.parse(params.inputParams) + : params.inputParams + } + if (params.dryRun !== undefined) body.dryRun = params.dryRun + if (params.updateCache !== undefined) body.updateCache = params.updateCache + if (params.updatePublishedResults !== undefined) + body.updatePublishedResults = params.updatePublishedResults + if (params.useCachedSqlResults !== undefined) + body.useCachedSqlResults = params.useCachedSqlResults + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + projectId: data.projectId ?? null, + runId: data.runId ?? null, + runUrl: data.runUrl ?? null, + runStatusUrl: data.runStatusUrl ?? null, + traceId: data.traceId ?? null, + projectVersion: data.projectVersion ?? null, + }, + } + }, + + outputs: { + projectId: HEX_RUN_OUTPUT_PROPERTIES.projectId, + runId: HEX_RUN_OUTPUT_PROPERTIES.runId, + runUrl: HEX_RUN_OUTPUT_PROPERTIES.runUrl, + runStatusUrl: HEX_RUN_OUTPUT_PROPERTIES.runStatusUrl, + traceId: HEX_RUN_OUTPUT_PROPERTIES.traceId, + projectVersion: HEX_RUN_OUTPUT_PROPERTIES.projectVersion, + }, +} diff --git a/apps/sim/tools/hex/types.ts b/apps/sim/tools/hex/types.ts new file mode 100644 index 0000000000..23b4321228 --- /dev/null +++ b/apps/sim/tools/hex/types.ts @@ -0,0 +1,429 @@ +import type { OutputProperty, ToolResponse } from '@/tools/types' + +/** + * Shared output property definitions for Hex API responses. + * Based on Hex API documentation: https://learn.hex.tech/docs/api/api-reference + */ + +/** + * Output definition for project items returned by the Hex API. + * The status field is an object with a name property (e.g., { name: "PUBLISHED" }). + * The type field is a ProjectTypeApiEnum (PROJECT or COMPONENT). + */ +export const HEX_PROJECT_OUTPUT_PROPERTIES = { + id: { type: 'string', description: 'Project UUID' }, + title: { type: 'string', description: 'Project title' }, + description: { type: 'string', description: 'Project description', optional: true }, + status: { + type: 'object', + description: 'Project status', + properties: { + name: { + type: 'string', + description: 'Status name (e.g., PUBLISHED, DRAFT)', + }, + }, + }, + type: { + type: 'string', + description: 'Project type (PROJECT or COMPONENT)', + }, + creator: { + type: 'object', + description: 'Project creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + }, + }, + owner: { + type: 'object', + description: 'Project owner', + optional: true, + properties: { + email: { type: 'string', description: 'Owner email' }, + }, + }, + categories: { + type: 'array', + description: 'Project categories', + optional: true, + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Category name' }, + description: { type: 'string', description: 'Category description' }, + }, + }, + }, + lastEditedAt: { type: 'string', description: 'ISO 8601 last edited timestamp', optional: true }, + lastPublishedAt: { + type: 'string', + description: 'ISO 8601 last published timestamp', + optional: true, + }, + createdAt: { type: 'string', description: 'ISO 8601 creation timestamp' }, + archivedAt: { type: 'string', description: 'ISO 8601 archived timestamp', optional: true }, + trashedAt: { type: 'string', description: 'ISO 8601 trashed timestamp', optional: true }, +} as const satisfies Record + +/** + * Output definition for run creation responses. + * POST /v1/projects/{projectId}/runs returns projectVersion but no status. + */ +export const HEX_RUN_OUTPUT_PROPERTIES = { + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID' }, + runUrl: { type: 'string', description: 'URL to view the run' }, + runStatusUrl: { type: 'string', description: 'URL to check run status' }, + traceId: { type: 'string', description: 'Trace ID for debugging', optional: true }, + projectVersion: { type: 'number', description: 'Project version number', optional: true }, +} as const satisfies Record + +/** + * Output definition for run status responses. + * GET /v1/projects/{projectId}/runs/{runId} returns full run details. + */ +export const HEX_RUN_STATUS_OUTPUT_PROPERTIES = { + projectId: { type: 'string', description: 'Project UUID' }, + runId: { type: 'string', description: 'Run UUID' }, + runUrl: { type: 'string', description: 'URL to view the run' }, + status: { + type: 'string', + description: + 'Run status (PENDING, RUNNING, COMPLETED, ERRORED, KILLED, UNABLE_TO_ALLOCATE_KERNEL)', + }, + startTime: { type: 'string', description: 'ISO 8601 run start time', optional: true }, + endTime: { type: 'string', description: 'ISO 8601 run end time', optional: true }, + elapsedTime: { type: 'number', description: 'Elapsed time in seconds', optional: true }, + traceId: { type: 'string', description: 'Trace ID for debugging', optional: true }, + projectVersion: { type: 'number', description: 'Project version number', optional: true }, +} as const satisfies Record + +export interface HexListProjectsParams { + apiKey: string + limit?: number + includeArchived?: boolean + statusFilter?: string +} + +export interface HexListProjectsResponse extends ToolResponse { + output: { + projects: Array<{ + id: string + title: string + description: string | null + status: { name: string } | null + type: string + creator: { email: string } | null + owner: { email: string } | null + categories: Array<{ name: string; description: string }> + lastEditedAt: string | null + lastPublishedAt: string | null + createdAt: string + archivedAt: string | null + trashedAt: string | null + }> + total: number + } +} + +export interface HexGetProjectParams { + apiKey: string + projectId: string +} + +export interface HexGetProjectResponse extends ToolResponse { + output: { + id: string + title: string + description: string | null + status: { name: string } | null + type: string + creator: { email: string } | null + owner: { email: string } | null + categories: Array<{ name: string; description: string }> + lastEditedAt: string | null + lastPublishedAt: string | null + createdAt: string + archivedAt: string | null + trashedAt: string | null + } +} + +export interface HexRunProjectParams { + apiKey: string + projectId: string + inputParams?: string + dryRun?: boolean + updateCache?: boolean + updatePublishedResults?: boolean + useCachedSqlResults?: boolean +} + +export interface HexRunProjectResponse extends ToolResponse { + output: { + projectId: string + runId: string + runUrl: string + runStatusUrl: string + traceId: string | null + projectVersion: number | null + } +} + +export interface HexGetRunStatusParams { + apiKey: string + projectId: string + runId: string +} + +export interface HexGetRunStatusResponse extends ToolResponse { + output: { + projectId: string + runId: string + runUrl: string | null + status: string + startTime: string | null + endTime: string | null + elapsedTime: number | null + traceId: string | null + projectVersion: number | null + } +} + +export interface HexCancelRunParams { + apiKey: string + projectId: string + runId: string +} + +export interface HexCancelRunResponse extends ToolResponse { + output: { + success: boolean + projectId: string + runId: string + } +} + +export interface HexGetProjectRunsParams { + apiKey: string + projectId: string + limit?: number + offset?: number + statusFilter?: string +} + +export interface HexGetProjectRunsResponse extends ToolResponse { + output: { + runs: Array<{ + projectId: string + runId: string + runUrl: string | null + status: string + startTime: string | null + endTime: string | null + elapsedTime: number | null + traceId: string | null + projectVersion: number | null + }> + total: number + traceId: string | null + } +} + +export interface HexUpdateProjectParams { + apiKey: string + projectId: string + status: string +} + +export interface HexUpdateProjectResponse extends ToolResponse { + output: { + id: string + title: string + description: string | null + status: { name: string } | null + type: string + creator: { email: string } | null + owner: { email: string } | null + categories: Array<{ name: string; description: string }> + lastEditedAt: string | null + lastPublishedAt: string | null + createdAt: string + archivedAt: string | null + trashedAt: string | null + } +} + +export interface HexListUsersParams { + apiKey: string + limit?: number + sortBy?: string + sortDirection?: string + groupId?: string +} + +export interface HexListUsersResponse extends ToolResponse { + output: { + users: Array<{ + id: string + name: string + email: string + role: string + }> + total: number + } +} + +export interface HexListCollectionsParams { + apiKey: string + limit?: number + sortBy?: string +} + +export interface HexListCollectionsResponse extends ToolResponse { + output: { + collections: Array<{ + id: string + name: string + description: string | null + creator: { email: string; id: string } | null + }> + total: number + } +} + +export interface HexListDataConnectionsParams { + apiKey: string + limit?: number + sortBy?: string + sortDirection?: string +} + +export interface HexListDataConnectionsResponse extends ToolResponse { + output: { + connections: Array<{ + id: string + name: string + type: string + description: string | null + connectViaSsh: boolean | null + includeMagic: boolean | null + allowWritebackCells: boolean | null + }> + total: number + } +} + +export interface HexGetQueriedTablesParams { + apiKey: string + projectId: string + limit?: number +} + +export interface HexGetQueriedTablesResponse extends ToolResponse { + output: { + tables: Array<{ + dataConnectionId: string | null + dataConnectionName: string | null + tableName: string | null + }> + total: number + } +} + +export interface HexListGroupsParams { + apiKey: string + limit?: number + sortBy?: string + sortDirection?: string +} + +export interface HexListGroupsResponse extends ToolResponse { + output: { + groups: Array<{ + id: string + name: string + createdAt: string | null + }> + total: number + } +} + +export interface HexGetGroupParams { + apiKey: string + groupId: string +} + +export interface HexGetGroupResponse extends ToolResponse { + output: { + id: string + name: string + createdAt: string | null + } +} + +export interface HexGetDataConnectionParams { + apiKey: string + dataConnectionId: string +} + +export interface HexGetDataConnectionResponse extends ToolResponse { + output: { + id: string + name: string + type: string + description: string | null + connectViaSsh: boolean | null + includeMagic: boolean | null + allowWritebackCells: boolean | null + } +} + +export interface HexGetCollectionParams { + apiKey: string + collectionId: string +} + +export interface HexGetCollectionResponse extends ToolResponse { + output: { + id: string + name: string + description: string | null + creator: { email: string; id: string } | null + } +} + +export interface HexCreateCollectionParams { + apiKey: string + name: string + description?: string +} + +export interface HexCreateCollectionResponse extends ToolResponse { + output: { + id: string + name: string + description: string | null + creator: { email: string; id: string } | null + } +} + +export type HexResponse = + | HexListProjectsResponse + | HexGetProjectResponse + | HexRunProjectResponse + | HexGetRunStatusResponse + | HexCancelRunResponse + | HexGetProjectRunsResponse + | HexUpdateProjectResponse + | HexListUsersResponse + | HexListCollectionsResponse + | HexListDataConnectionsResponse + | HexGetQueriedTablesResponse + | HexListGroupsResponse + | HexGetGroupResponse + | HexGetDataConnectionResponse + | HexGetCollectionResponse + | HexCreateCollectionResponse diff --git a/apps/sim/tools/hex/update_project.ts b/apps/sim/tools/hex/update_project.ts new file mode 100644 index 0000000000..e8da0a3c27 --- /dev/null +++ b/apps/sim/tools/hex/update_project.ts @@ -0,0 +1,118 @@ +import type { HexUpdateProjectParams, HexUpdateProjectResponse } from '@/tools/hex/types' +import type { ToolConfig } from '@/tools/types' + +export const updateProjectTool: ToolConfig = { + id: 'hex_update_project', + name: 'Hex Update Project', + description: + 'Update a Hex project status label (e.g., endorsement or custom workspace statuses).', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Hex API token (Personal or Workspace)', + }, + projectId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The UUID of the Hex project to update', + }, + status: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'New project status name (custom workspace status label)', + }, + }, + + request: { + url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}`, + method: 'PATCH', + headers: (params) => ({ + Authorization: `Bearer ${params.apiKey}`, + 'Content-Type': 'application/json', + }), + body: (params) => ({ + status: params.status, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + + return { + success: true, + output: { + id: data.id ?? null, + title: data.title ?? null, + description: data.description ?? null, + status: data.status ? { name: data.status.name ?? null } : null, + type: data.type ?? null, + creator: data.creator ? { email: data.creator.email ?? null } : null, + owner: data.owner ? { email: data.owner.email ?? null } : null, + categories: Array.isArray(data.categories) + ? data.categories.map((c: Record) => ({ + name: c.name ?? null, + description: c.description ?? null, + })) + : [], + lastEditedAt: data.lastEditedAt ?? null, + lastPublishedAt: data.lastPublishedAt ?? null, + createdAt: data.createdAt ?? null, + archivedAt: data.archivedAt ?? null, + trashedAt: data.trashedAt ?? null, + }, + } + }, + + outputs: { + id: { type: 'string', description: 'Project UUID' }, + title: { type: 'string', description: 'Project title' }, + description: { type: 'string', description: 'Project description', optional: true }, + status: { + type: 'object', + description: 'Updated project status', + properties: { + name: { type: 'string', description: 'Status name (e.g., PUBLISHED, DRAFT)' }, + }, + }, + type: { type: 'string', description: 'Project type (PROJECT or COMPONENT)' }, + creator: { + type: 'object', + description: 'Project creator', + optional: true, + properties: { + email: { type: 'string', description: 'Creator email' }, + }, + }, + owner: { + type: 'object', + description: 'Project owner', + optional: true, + properties: { + email: { type: 'string', description: 'Owner email' }, + }, + }, + categories: { + type: 'array', + description: 'Project categories', + optional: true, + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Category name' }, + description: { type: 'string', description: 'Category description' }, + }, + }, + }, + lastEditedAt: { type: 'string', description: 'Last edited timestamp', optional: true }, + lastPublishedAt: { type: 'string', description: 'Last published timestamp', optional: true }, + createdAt: { type: 'string', description: 'Creation timestamp' }, + archivedAt: { type: 'string', description: 'Archived timestamp', optional: true }, + trashedAt: { type: 'string', description: 'Trashed timestamp', optional: true }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index c206509aca..7642dfa0bb 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -723,6 +723,24 @@ import { greptileStatusTool, } from '@/tools/greptile' import { guardrailsValidateTool } from '@/tools/guardrails' +import { + hexCancelRunTool, + hexCreateCollectionTool, + hexGetCollectionTool, + hexGetDataConnectionTool, + hexGetGroupTool, + hexGetProjectRunsTool, + hexGetProjectTool, + hexGetQueriedTablesTool, + hexGetRunStatusTool, + hexListCollectionsTool, + hexListDataConnectionsTool, + hexListGroupsTool, + hexListProjectsTool, + hexListUsersTool, + hexRunProjectTool, + hexUpdateProjectTool, +} from '@/tools/hex' import { httpRequestTool, webhookRequestTool } from '@/tools/http' import { hubspotCreateCompanyTool, @@ -2058,6 +2076,22 @@ export const tools: Record = { grafana_create_folder: grafanaCreateFolderTool, google_search: googleSearchTool, guardrails_validate: guardrailsValidateTool, + hex_cancel_run: hexCancelRunTool, + hex_create_collection: hexCreateCollectionTool, + hex_get_collection: hexGetCollectionTool, + hex_get_data_connection: hexGetDataConnectionTool, + hex_get_group: hexGetGroupTool, + hex_get_project: hexGetProjectTool, + hex_get_project_runs: hexGetProjectRunsTool, + hex_get_queried_tables: hexGetQueriedTablesTool, + hex_get_run_status: hexGetRunStatusTool, + hex_list_collections: hexListCollectionsTool, + hex_list_data_connections: hexListDataConnectionsTool, + hex_list_groups: hexListGroupsTool, + hex_list_projects: hexListProjectsTool, + hex_list_users: hexListUsersTool, + hex_run_project: hexRunProjectTool, + hex_update_project: hexUpdateProjectTool, jina_read_url: jinaReadUrlTool, jina_search: jinaSearchTool, linkup_search: linkupSearchTool,