mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(hex): expand API coverage, fix ID trimming, add cursor pagination (#5372)
* feat(hex): expand API coverage, fix ID trimming, add cursor pagination - Add hex_update_collection, hex_create_group, hex_update_group, hex_delete_group, hex_deactivate_user tools + block wiring - Add missing run_project fields (viewId, notifications) and get_project_runs runTriggerFilter - Add after/before cursor pagination to list_projects, list_groups, list_data_connections, list_collections - Add .trim() on all interpolated ID path params to guard against copy-paste whitespace * fix(hex): guard JSON.parse on user-supplied array/object params Wrap JSON.parse calls for memberUserIds, addUserIds, removeUserIds, inputParams, and notifications in try/catch so malformed input throws a clear error instead of an opaque parse exception. * fix(hex): forward empty collection description on update update_collection's params() mapping only copied collectionDescription when truthy, so clearing it to an empty string in the UI never reached the API. Untouched fields resolve to null (not undefined), so use a loose null check to distinguish "cleared" from "never touched" without sending description: null on every unrelated update. * fix(hex): close remaining API coverage gaps found via raw OpenAPI spec Pulled Hex's actual OpenAPI spec (static.hex.site/openapi.json) as ground truth for a final verification pass: - list_users was missing after/before cursor pagination and the userIds filter, which the spec confirms it supports (an earlier doc-summary pass had incorrectly flagged this as unverifiable) - list_users response also exposes lastLoginDate per user, not previously surfaced - list_projects was missing includeComponents, includeTrashed, creatorEmail, ownerEmail, collectionId, categories, sortBy, and sortDirection filters that the spec confirms are real query params * fix(hex): trim remaining user-suppliable IDs for consistency Trim collectionId (list_projects filter), viewId (run_project body), and group member UUIDs (create_group/update_group) to match the .trim() convention already applied to path-segment IDs elsewhere. * fix(hex): validate parsed JSON is actually an array before iterating categories, memberUserIds, addUserIds, and removeUserIds could parse as valid JSON that isn't an array (e.g. an object), which would throw an opaque "not iterable"/"map is not a function" error deeper in the call. Validate Array.isArray after parsing and fail with a clear message instead. * fix(hex): validate array element types, send explicit ALL trigger filter - notifications now gets the same Array.isArray guard already applied to categories/memberUserIds/addUserIds/removeUserIds - member/category array elements are now validated as strings before .trim()/append, instead of crashing on non-string entries - runTriggerFilter "All" option now sends the documented ALL enum value explicitly instead of relying on omission
This commit is contained in:
+324
-12
@@ -8,7 +8,7 @@ export const HexBlock: BlockConfig<HexResponse> = {
|
||||
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.',
|
||||
'Integrate Hex into your workflow. Run projects, check run status, manage collections and groups (including membership and deactivating users), list users, and view data connections. Requires a Hex API token.',
|
||||
docsLink: 'https://docs.sim.ai/integrations/hex',
|
||||
category: 'tools',
|
||||
integrationType: IntegrationType.Analytics,
|
||||
@@ -36,8 +36,13 @@ export const HexBlock: BlockConfig<HexResponse> = {
|
||||
{ label: 'List Collections', id: 'list_collections' },
|
||||
{ label: 'Get Collection', id: 'get_collection' },
|
||||
{ label: 'Create Collection', id: 'create_collection' },
|
||||
{ label: 'Update Collection', id: 'update_collection' },
|
||||
{ label: 'List Data Connections', id: 'list_data_connections' },
|
||||
{ label: 'Get Data Connection', id: 'get_data_connection' },
|
||||
{ label: 'Create Group', id: 'create_group' },
|
||||
{ label: 'Update Group', id: 'update_group' },
|
||||
{ label: 'Delete Group', id: 'delete_group' },
|
||||
{ label: 'Deactivate User', id: 'deactivate_user' },
|
||||
],
|
||||
value: () => 'run_project',
|
||||
},
|
||||
@@ -107,6 +112,39 @@ Example:
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'viewId',
|
||||
title: 'Saved View ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter a SavedView UUID (optional)',
|
||||
condition: { field: 'operation', value: 'run_project' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'notifications',
|
||||
title: 'Notifications',
|
||||
type: 'code',
|
||||
placeholder: '[{"type": "FAILURE", "slackChannelIds": ["C0123456789"]}]',
|
||||
condition: { field: 'operation', value: 'run_project' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
maintainHistory: true,
|
||||
prompt: `You are an expert at creating Hex run notification configs.
|
||||
Generate ONLY the raw JSON array based on the user's request.
|
||||
The output MUST be a single, valid JSON array, starting with [ and ending with ].
|
||||
|
||||
Current value: {context}
|
||||
|
||||
Do not include any explanations, markdown formatting, or other text outside the JSON array.
|
||||
Each item's "type" must be one of ALL, SUCCESS, or FAILURE. Optional fields: includeSuccessScreenshot (boolean), slackChannelIds, userIds, groupIds (arrays of strings).
|
||||
|
||||
Example:
|
||||
[{"type": "FAILURE", "slackChannelIds": ["C0123456789"], "includeSuccessScreenshot": false}]`,
|
||||
placeholder: 'Describe who should be notified and when...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'projectStatus',
|
||||
title: 'Status',
|
||||
@@ -130,28 +168,119 @@ Example:
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'get_project_runs' },
|
||||
},
|
||||
{
|
||||
id: 'runTriggerFilter',
|
||||
title: 'Trigger Filter',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'All', id: 'ALL' },
|
||||
{ label: 'API', id: 'API' },
|
||||
{ label: 'Scheduled', id: 'SCHEDULED' },
|
||||
{ label: 'App Refresh', id: 'APP_REFRESH' },
|
||||
],
|
||||
value: () => 'ALL',
|
||||
condition: { field: 'operation', value: 'get_project_runs' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'groupIdInput',
|
||||
title: 'Group ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter group UUID',
|
||||
condition: { field: 'operation', value: 'get_group' },
|
||||
required: { field: 'operation', value: 'get_group' },
|
||||
condition: { field: 'operation', value: ['get_group', 'update_group', 'delete_group'] },
|
||||
required: { field: 'operation', value: ['get_group', 'update_group', 'delete_group'] },
|
||||
},
|
||||
{
|
||||
id: 'groupName',
|
||||
title: 'Group Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter group name',
|
||||
condition: { field: 'operation', value: ['create_group', 'update_group'] },
|
||||
required: { field: 'operation', value: 'create_group' },
|
||||
},
|
||||
{
|
||||
id: 'groupMemberUserIds',
|
||||
title: 'Initial Member User IDs',
|
||||
type: 'code',
|
||||
placeholder: '["uuid1", "uuid2"]',
|
||||
condition: { field: 'operation', value: 'create_group' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
maintainHistory: true,
|
||||
prompt: `You are an expert at creating JSON arrays of user UUIDs.
|
||||
Generate ONLY the raw JSON array of user ID strings based on the user's request.
|
||||
The output MUST be a single, valid JSON array of strings, starting with [ and ending with ].
|
||||
|
||||
Current value: {context}
|
||||
|
||||
Do not include any explanations, markdown formatting, or other text outside the JSON array.
|
||||
|
||||
Example:
|
||||
["a1b2c3d4-0000-0000-0000-000000000000", "e5f6a7b8-0000-0000-0000-000000000000"]`,
|
||||
placeholder: 'Describe which users to add...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'groupAddUserIds',
|
||||
title: 'Add Member User IDs',
|
||||
type: 'code',
|
||||
placeholder: '["uuid1", "uuid2"]',
|
||||
condition: { field: 'operation', value: 'update_group' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
maintainHistory: true,
|
||||
prompt: `You are an expert at creating JSON arrays of user UUIDs.
|
||||
Generate ONLY the raw JSON array of user ID strings to add based on the user's request.
|
||||
The output MUST be a single, valid JSON array of strings, starting with [ and ending with ].
|
||||
|
||||
Current value: {context}
|
||||
|
||||
Do not include any explanations, markdown formatting, or other text outside the JSON array.`,
|
||||
placeholder: 'Describe which users to add...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'groupRemoveUserIds',
|
||||
title: 'Remove Member User IDs',
|
||||
type: 'code',
|
||||
placeholder: '["uuid1", "uuid2"]',
|
||||
condition: { field: 'operation', value: 'update_group' },
|
||||
mode: 'advanced',
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
maintainHistory: true,
|
||||
prompt: `You are an expert at creating JSON arrays of user UUIDs.
|
||||
Generate ONLY the raw JSON array of user ID strings to remove based on the user's request.
|
||||
The output MUST be a single, valid JSON array of strings, starting with [ and ending with ].
|
||||
|
||||
Current value: {context}
|
||||
|
||||
Do not include any explanations, markdown formatting, or other text outside the JSON array.`,
|
||||
placeholder: 'Describe which users to remove...',
|
||||
generationType: 'json-object',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'collectionId',
|
||||
title: 'Collection ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter collection UUID',
|
||||
condition: { field: 'operation', value: 'get_collection' },
|
||||
required: { field: 'operation', value: 'get_collection' },
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: ['get_collection', 'update_collection', 'list_projects'],
|
||||
},
|
||||
required: { field: 'operation', value: ['get_collection', 'update_collection'] },
|
||||
},
|
||||
{
|
||||
id: 'collectionName',
|
||||
title: 'Collection Name',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter collection name',
|
||||
condition: { field: 'operation', value: 'create_collection' },
|
||||
condition: { field: 'operation', value: ['create_collection', 'update_collection'] },
|
||||
required: { field: 'operation', value: 'create_collection' },
|
||||
},
|
||||
{
|
||||
@@ -159,7 +288,7 @@ Example:
|
||||
title: 'Description',
|
||||
type: 'long-input',
|
||||
placeholder: 'Optional description for the collection',
|
||||
condition: { field: 'operation', value: 'create_collection' },
|
||||
condition: { field: 'operation', value: ['create_collection', 'update_collection'] },
|
||||
},
|
||||
{
|
||||
id: 'dataConnectionId',
|
||||
@@ -169,6 +298,14 @@ Example:
|
||||
condition: { field: 'operation', value: 'get_data_connection' },
|
||||
required: { field: 'operation', value: 'get_data_connection' },
|
||||
},
|
||||
{
|
||||
id: 'userId',
|
||||
title: 'User ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter user UUID',
|
||||
condition: { field: 'operation', value: 'deactivate_user' },
|
||||
required: { field: 'operation', value: 'deactivate_user' },
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
@@ -240,6 +377,20 @@ Example:
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'includeComponents',
|
||||
title: 'Include Components',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'includeTrashed',
|
||||
title: 'Include Trashed',
|
||||
type: 'switch',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'statusFilter',
|
||||
title: 'Status Filter',
|
||||
@@ -253,6 +404,57 @@ Example:
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'creatorEmail',
|
||||
title: 'Creator Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Filter by creator email (optional)',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'ownerEmail',
|
||||
title: 'Owner Email',
|
||||
type: 'short-input',
|
||||
placeholder: 'Filter by owner email (optional)',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'categories',
|
||||
title: 'Categories',
|
||||
type: 'code',
|
||||
placeholder: '["Marketing", "Finance"]',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'sortBy',
|
||||
title: 'Sort By',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Default', id: '' },
|
||||
{ label: 'Created At', id: 'CREATED_AT' },
|
||||
{ label: 'Last Edited At', id: 'LAST_EDITED_AT' },
|
||||
{ label: 'Last Published At', id: 'LAST_PUBLISHED_AT' },
|
||||
],
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'sortDirection',
|
||||
title: 'Sort Direction',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Default', id: '' },
|
||||
{ label: 'Ascending', id: 'ASC' },
|
||||
{ label: 'Descending', id: 'DESC' },
|
||||
],
|
||||
value: () => '',
|
||||
condition: { field: 'operation', value: 'list_projects' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'groupId',
|
||||
title: 'Filter by Group',
|
||||
@@ -261,12 +463,57 @@ Example:
|
||||
condition: { field: 'operation', value: 'list_users' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'userIds',
|
||||
title: 'Filter by User IDs',
|
||||
type: 'short-input',
|
||||
placeholder: 'Comma-separated user UUIDs (optional)',
|
||||
condition: { field: 'operation', value: 'list_users' },
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'after',
|
||||
title: 'After Cursor',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cursor for the next page',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'list_projects',
|
||||
'list_groups',
|
||||
'list_collections',
|
||||
'list_data_connections',
|
||||
'list_users',
|
||||
],
|
||||
},
|
||||
mode: 'advanced',
|
||||
},
|
||||
{
|
||||
id: 'before',
|
||||
title: 'Before Cursor',
|
||||
type: 'short-input',
|
||||
placeholder: 'Cursor for the previous page',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: [
|
||||
'list_projects',
|
||||
'list_groups',
|
||||
'list_collections',
|
||||
'list_data_connections',
|
||||
'list_users',
|
||||
],
|
||||
},
|
||||
mode: 'advanced',
|
||||
},
|
||||
],
|
||||
|
||||
tools: {
|
||||
access: [
|
||||
'hex_cancel_run',
|
||||
'hex_create_collection',
|
||||
'hex_create_group',
|
||||
'hex_deactivate_user',
|
||||
'hex_delete_group',
|
||||
'hex_get_collection',
|
||||
'hex_get_data_connection',
|
||||
'hex_get_group',
|
||||
@@ -280,6 +527,8 @@ Example:
|
||||
'hex_list_projects',
|
||||
'hex_list_users',
|
||||
'hex_run_project',
|
||||
'hex_update_collection',
|
||||
'hex_update_group',
|
||||
'hex_update_project',
|
||||
],
|
||||
config: {
|
||||
@@ -313,10 +562,20 @@ Example:
|
||||
return 'hex_get_collection'
|
||||
case 'create_collection':
|
||||
return 'hex_create_collection'
|
||||
case 'update_collection':
|
||||
return 'hex_update_collection'
|
||||
case 'list_data_connections':
|
||||
return 'hex_list_data_connections'
|
||||
case 'get_data_connection':
|
||||
return 'hex_get_data_connection'
|
||||
case 'create_group':
|
||||
return 'hex_create_group'
|
||||
case 'update_group':
|
||||
return 'hex_update_group'
|
||||
case 'delete_group':
|
||||
return 'hex_delete_group'
|
||||
case 'deactivate_user':
|
||||
return 'hex_deactivate_user'
|
||||
default:
|
||||
return 'hex_run_project'
|
||||
}
|
||||
@@ -330,11 +589,26 @@ Example:
|
||||
if (op === 'update_project' && params.projectStatus) result.status = params.projectStatus
|
||||
if (op === 'get_project_runs' && params.runStatusFilter)
|
||||
result.statusFilter = params.runStatusFilter
|
||||
if (op === 'get_group' && params.groupIdInput) result.groupId = params.groupIdInput
|
||||
if (
|
||||
(op === 'get_group' || op === 'update_group' || op === 'delete_group') &&
|
||||
params.groupIdInput
|
||||
)
|
||||
result.groupId = params.groupIdInput
|
||||
if (op === 'list_users' && params.groupId) result.groupId = params.groupId
|
||||
if (op === 'create_collection' && params.collectionName) result.name = params.collectionName
|
||||
if ((op === 'create_collection' || op === 'update_collection') && params.collectionName)
|
||||
result.name = params.collectionName
|
||||
if (op === 'create_collection' && params.collectionDescription)
|
||||
result.description = params.collectionDescription
|
||||
if (op === 'update_collection' && params.collectionDescription != null)
|
||||
result.description = params.collectionDescription
|
||||
if ((op === 'create_group' || op === 'update_group') && params.groupName)
|
||||
result.name = params.groupName
|
||||
if (op === 'create_group' && params.groupMemberUserIds)
|
||||
result.memberUserIds = params.groupMemberUserIds
|
||||
if (op === 'update_group' && params.groupAddUserIds)
|
||||
result.addUserIds = params.groupAddUserIds
|
||||
if (op === 'update_group' && params.groupRemoveUserIds)
|
||||
result.removeUserIds = params.groupRemoveUserIds
|
||||
|
||||
return result
|
||||
},
|
||||
@@ -360,21 +634,42 @@ Example:
|
||||
type: 'boolean',
|
||||
description: 'Use cached SQL results instead of re-running queries',
|
||||
},
|
||||
viewId: { type: 'string', description: 'SavedView UUID to use for the project run' },
|
||||
notifications: {
|
||||
type: 'json',
|
||||
description: 'Notification details to deliver once the run completes',
|
||||
},
|
||||
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' },
|
||||
after: { type: 'string', description: 'Cursor to fetch results after' },
|
||||
before: { type: 'string', description: 'Cursor to fetch results before' },
|
||||
includeArchived: { type: 'boolean', description: 'Include archived projects' },
|
||||
includeComponents: { type: 'boolean', description: 'Include components in results' },
|
||||
includeTrashed: { type: 'boolean', description: 'Include trashed projects in results' },
|
||||
statusFilter: { type: 'string', description: 'Filter projects by status' },
|
||||
creatorEmail: { type: 'string', description: 'Filter projects by creator email' },
|
||||
ownerEmail: { type: 'string', description: 'Filter projects by owner email' },
|
||||
categories: { type: 'json', description: 'Filter projects by category names' },
|
||||
sortBy: { type: 'string', description: 'Sort field for list results' },
|
||||
sortDirection: { type: 'string', description: 'Sort direction for list results' },
|
||||
runStatusFilter: { type: 'string', description: 'Filter runs by status' },
|
||||
runTriggerFilter: { type: 'string', description: 'Filter runs by trigger source' },
|
||||
groupId: { type: 'string', description: 'Filter users by group UUID' },
|
||||
groupIdInput: { type: 'string', description: 'Group UUID for get group' },
|
||||
userIds: { type: 'string', description: 'Comma-separated user UUIDs to filter by' },
|
||||
groupIdInput: { type: 'string', description: 'Group UUID for get/update/delete group' },
|
||||
groupName: { type: 'string', description: 'Group name' },
|
||||
groupMemberUserIds: { type: 'json', description: 'Initial member user UUIDs for new group' },
|
||||
groupAddUserIds: { type: 'json', description: 'User UUIDs to add to the group' },
|
||||
groupRemoveUserIds: { type: 'json', description: 'User UUIDs to remove from the 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' },
|
||||
userId: { type: 'string', description: 'User UUID' },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
@@ -415,7 +710,10 @@ Example:
|
||||
description:
|
||||
'List of runs with runId, status, runUrl, startTime, endTime, elapsedTime, projectVersion',
|
||||
},
|
||||
users: { type: 'json', description: 'List of users with id, name, email, role' },
|
||||
users: {
|
||||
type: 'json',
|
||||
description: 'List of users with id, name, email, role, lastLoginDate',
|
||||
},
|
||||
groups: { type: 'json', description: 'List of groups with id, name, createdAt' },
|
||||
collections: {
|
||||
type: 'json',
|
||||
@@ -437,8 +735,15 @@ Example:
|
||||
creator: { type: 'json', description: 'Creator details ({ email, id })' },
|
||||
owner: { type: 'json', description: 'Owner details ({ email })' },
|
||||
total: { type: 'number', description: 'Total results returned' },
|
||||
// Cancel output
|
||||
// Cancel / delete / deactivate output
|
||||
success: { type: 'boolean', description: 'Whether the operation succeeded' },
|
||||
groupId: { type: 'string', description: 'Group UUID' },
|
||||
userId: { type: 'string', description: 'User UUID' },
|
||||
// Pagination
|
||||
nextPage: { type: 'string', description: 'Cursor for the next page of runs' },
|
||||
previousPage: { type: 'string', description: 'Cursor for the previous page of runs' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results' },
|
||||
before: { type: 'string', description: 'Cursor for the previous page of results' },
|
||||
// Data connection flags
|
||||
connectViaSsh: { type: 'boolean', description: 'SSH tunneling enabled' },
|
||||
includeMagic: { type: 'boolean', description: 'Magic AI features enabled' },
|
||||
@@ -546,5 +851,12 @@ export const HexBlockMeta = {
|
||||
content:
|
||||
'# Inventory Projects\n\nMap what projects and data sources exist in the workspace.\n\n## Steps\n1. List projects and capture IDs, names, and owners.\n2. List collections and get details to see how projects are grouped.\n3. List data connections to map which sources power the projects.\n4. Cross-reference projects to their collections and data connections.\n\n## Output\nReturn an inventory of projects grouped by collection, each annotated with its data connections. Useful for governance and cleanup.',
|
||||
},
|
||||
{
|
||||
name: 'onboard-offboard-teammate',
|
||||
description:
|
||||
'Add a new teammate to the right Hex groups on hire, or deactivate and remove them on departure.',
|
||||
content:
|
||||
'# Onboard/Offboard Teammate\n\nManage workspace access as people join or leave the team.\n\n## Steps\n1. List users to resolve the target user by name or email, and list groups to resolve the relevant group by name.\n2. For onboarding: add the user to the appropriate group(s) via group update.\n3. For offboarding: remove the user from their groups via group update, then deactivate the user account.\n4. Confirm the change by getting the group or listing users filtered by group.\n\n## Output\nReturn the user and group IDs affected and the action taken (added, removed, deactivated). Flag if the user or group could not be resolved.',
|
||||
},
|
||||
],
|
||||
} as const satisfies BlockMeta
|
||||
|
||||
@@ -30,7 +30,7 @@ export const cancelRunTool: ToolConfig<HexCancelRunParams, HexCancelRunResponse>
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://app.hex.tech/api/v1/projects/${params.projectId}/runs/${params.runId}`,
|
||||
`https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs/${params.runId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import type { HexCreateGroupParams, HexCreateGroupResponse } from '@/tools/hex/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const createGroupTool: ToolConfig<HexCreateGroupParams, HexCreateGroupResponse> = {
|
||||
id: 'hex_create_group',
|
||||
name: 'Hex Create Group',
|
||||
description: 'Create a new group in the Hex workspace, optionally with initial members.',
|
||||
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 group',
|
||||
},
|
||||
memberUserIds: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of user UUIDs to add as initial group members (e.g., ["uuid1", "uuid2"])',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://app.hex.tech/api/v1/groups',
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = { name: params.name }
|
||||
if (params.memberUserIds) {
|
||||
let userIds: unknown
|
||||
try {
|
||||
userIds =
|
||||
typeof params.memberUserIds === 'string'
|
||||
? JSON.parse(params.memberUserIds)
|
||||
: params.memberUserIds
|
||||
} catch {
|
||||
throw new Error('memberUserIds must be a valid JSON array of user UUID strings')
|
||||
}
|
||||
if (!Array.isArray(userIds) || !userIds.every((id) => typeof id === 'string')) {
|
||||
throw new Error('memberUserIds must be a valid JSON array of user UUID strings')
|
||||
}
|
||||
body.members = { users: userIds.map((id: string) => ({ id: id.trim() })) }
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
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: 'Newly created group UUID' },
|
||||
name: { type: 'string', description: 'Group name' },
|
||||
createdAt: { type: 'string', description: 'Creation timestamp' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import type { HexDeactivateUserParams, HexDeactivateUserResponse } from '@/tools/hex/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const deactivateUserTool: ToolConfig<HexDeactivateUserParams, HexDeactivateUserResponse> = {
|
||||
id: 'hex_deactivate_user',
|
||||
name: 'Hex Deactivate User',
|
||||
description: 'Deactivate a user in the Hex workspace.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Hex API token (Personal or Workspace)',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The UUID of the user to deactivate',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/users/${params.userId.trim()}/deactivate`,
|
||||
method: 'POST',
|
||||
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,
|
||||
userId: params?.userId ?? '',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
success: false,
|
||||
userId: params?.userId ?? '',
|
||||
},
|
||||
error: (data as Record<string, string>).message ?? 'Failed to deactivate user',
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: { type: 'boolean', description: 'Whether the user was successfully deactivated' },
|
||||
userId: { type: 'string', description: 'User UUID that was deactivated' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import type { HexDeleteGroupParams, HexDeleteGroupResponse } from '@/tools/hex/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const deleteGroupTool: ToolConfig<HexDeleteGroupParams, HexDeleteGroupResponse> = {
|
||||
id: 'hex_delete_group',
|
||||
name: 'Hex Delete Group',
|
||||
description: 'Delete a group from the Hex workspace.',
|
||||
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 to delete',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId.trim()}`,
|
||||
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,
|
||||
groupId: params?.groupId ?? '',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const data = await response.json().catch(() => ({}))
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
success: false,
|
||||
groupId: params?.groupId ?? '',
|
||||
},
|
||||
error: (data as Record<string, string>).message ?? 'Failed to delete group',
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
success: { type: 'boolean', description: 'Whether the group was successfully deleted' },
|
||||
groupId: { type: 'string', description: 'Group UUID that was deleted' },
|
||||
},
|
||||
}
|
||||
@@ -23,7 +23,7 @@ export const getCollectionTool: ToolConfig<HexGetCollectionParams, HexGetCollect
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId}`,
|
||||
url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -27,7 +27,8 @@ export const getDataConnectionTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/data-connections/${params.dataConnectionId}`,
|
||||
url: (params) =>
|
||||
`https://app.hex.tech/api/v1/data-connections/${params.dataConnectionId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -23,7 +23,7 @@ export const getGroupTool: ToolConfig<HexGetGroupParams, HexGetGroupResponse> =
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId}`,
|
||||
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -24,7 +24,7 @@ export const getProjectTool: ToolConfig<HexGetProjectParams, HexGetProjectRespon
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}`,
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -40,6 +40,12 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
|
||||
description:
|
||||
'Filter by run status: PENDING, RUNNING, ERRORED, COMPLETED, KILLED, UNABLE_TO_ALLOCATE_KERNEL',
|
||||
},
|
||||
runTriggerFilter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by how the run was triggered: ALL, API, SCHEDULED, or APP_REFRESH',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -48,8 +54,9 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
|
||||
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)
|
||||
if (params.runTriggerFilter) searchParams.set('runTriggerFilter', params.runTriggerFilter)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/projects/${params.projectId}/runs${qs ? `?${qs}` : ''}`
|
||||
return `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
@@ -78,6 +85,8 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
|
||||
})),
|
||||
total: runs.length,
|
||||
traceId: data.traceId ?? null,
|
||||
nextPage: data.nextPage ?? null,
|
||||
previousPage: data.previousPage ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -111,5 +120,11 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of runs returned' },
|
||||
traceId: { type: 'string', description: 'Top-level trace ID', optional: true },
|
||||
nextPage: { type: 'string', description: 'Cursor for the next page of runs', optional: true },
|
||||
previousPage: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of runs',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export const getQueriedTablesTool: ToolConfig<
|
||||
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}` : ''}`
|
||||
return `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/queriedTables${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
|
||||
@@ -31,7 +31,7 @@ export const getRunStatusTool: ToolConfig<HexGetRunStatusParams, HexGetRunStatus
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://app.hex.tech/api/v1/projects/${params.projectId}/runs/${params.runId}`,
|
||||
`https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs/${params.runId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { cancelRunTool } from '@/tools/hex/cancel_run'
|
||||
import { createCollectionTool } from '@/tools/hex/create_collection'
|
||||
import { createGroupTool } from '@/tools/hex/create_group'
|
||||
import { deactivateUserTool } from '@/tools/hex/deactivate_user'
|
||||
import { deleteGroupTool } from '@/tools/hex/delete_group'
|
||||
import { getCollectionTool } from '@/tools/hex/get_collection'
|
||||
import { getDataConnectionTool } from '@/tools/hex/get_data_connection'
|
||||
import { getGroupTool } from '@/tools/hex/get_group'
|
||||
@@ -13,10 +16,15 @@ 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 { updateCollectionTool } from '@/tools/hex/update_collection'
|
||||
import { updateGroupTool } from '@/tools/hex/update_group'
|
||||
import { updateProjectTool } from '@/tools/hex/update_project'
|
||||
|
||||
export const hexCancelRunTool = cancelRunTool
|
||||
export const hexCreateCollectionTool = createCollectionTool
|
||||
export const hexCreateGroupTool = createGroupTool
|
||||
export const hexDeactivateUserTool = deactivateUserTool
|
||||
export const hexDeleteGroupTool = deleteGroupTool
|
||||
export const hexGetCollectionTool = getCollectionTool
|
||||
export const hexGetDataConnectionTool = getDataConnectionTool
|
||||
export const hexGetGroupTool = getGroupTool
|
||||
@@ -30,4 +38,6 @@ export const hexListGroupsTool = listGroupsTool
|
||||
export const hexListProjectsTool = listProjectsTool
|
||||
export const hexListUsersTool = listUsersTool
|
||||
export const hexRunProjectTool = runProjectTool
|
||||
export const hexUpdateCollectionTool = updateCollectionTool
|
||||
export const hexUpdateGroupTool = updateGroupTool
|
||||
export const hexUpdateProjectTool = updateProjectTool
|
||||
|
||||
@@ -27,6 +27,18 @@ export const listCollectionsTool: ToolConfig<HexListCollectionsParams, HexListCo
|
||||
visibility: 'user-only',
|
||||
description: 'Sort by field: NAME',
|
||||
},
|
||||
after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results after this value',
|
||||
},
|
||||
before: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results before this value',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -34,6 +46,8 @@ export const listCollectionsTool: ToolConfig<HexListCollectionsParams, HexListCo
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params.limit) searchParams.set('limit', String(params.limit))
|
||||
if (params.sortBy) searchParams.set('sortBy', params.sortBy)
|
||||
if (params.after) searchParams.set('after', params.after)
|
||||
if (params.before) searchParams.set('before', params.before)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/collections${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
@@ -63,6 +77,8 @@ export const listCollectionsTool: ToolConfig<HexListCollectionsParams, HexListCo
|
||||
: null,
|
||||
})),
|
||||
total: collections.length,
|
||||
after: data.pagination?.after ?? null,
|
||||
before: data.pagination?.before ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -90,5 +106,11 @@ export const listCollectionsTool: ToolConfig<HexListCollectionsParams, HexListCo
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of collections returned' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results', optional: true },
|
||||
before: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -39,6 +39,18 @@ export const listDataConnectionsTool: ToolConfig<
|
||||
visibility: 'user-only',
|
||||
description: 'Sort direction: ASC or DESC',
|
||||
},
|
||||
after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results after this value',
|
||||
},
|
||||
before: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results before this value',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -47,6 +59,8 @@ export const listDataConnectionsTool: ToolConfig<
|
||||
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.after) searchParams.set('after', params.after)
|
||||
if (params.before) searchParams.set('before', params.before)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/data-connections${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
@@ -74,6 +88,8 @@ export const listDataConnectionsTool: ToolConfig<
|
||||
allowWritebackCells: (c.allowWritebackCells as boolean) ?? null,
|
||||
})),
|
||||
total: connections.length,
|
||||
after: data.pagination?.after ?? null,
|
||||
before: data.pagination?.before ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -112,5 +128,11 @@ export const listDataConnectionsTool: ToolConfig<
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of connections returned' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results', optional: true },
|
||||
before: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,6 +32,18 @@ export const listGroupsTool: ToolConfig<HexListGroupsParams, HexListGroupsRespon
|
||||
visibility: 'user-only',
|
||||
description: 'Sort direction: ASC or DESC',
|
||||
},
|
||||
after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results after this value',
|
||||
},
|
||||
before: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results before this value',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -40,6 +52,8 @@ export const listGroupsTool: ToolConfig<HexListGroupsParams, HexListGroupsRespon
|
||||
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.after) searchParams.set('after', params.after)
|
||||
if (params.before) searchParams.set('before', params.before)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/groups${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
@@ -63,6 +77,8 @@ export const listGroupsTool: ToolConfig<HexListGroupsParams, HexListGroupsRespon
|
||||
createdAt: (g.createdAt as string) ?? null,
|
||||
})),
|
||||
total: groups.length,
|
||||
after: data.pagination?.after ?? null,
|
||||
before: data.pagination?.before ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -81,5 +97,11 @@ export const listGroupsTool: ToolConfig<HexListGroupsParams, HexListGroupsRespon
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of groups returned' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results', optional: true },
|
||||
before: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,6 +32,66 @@ export const listProjectsTool: ToolConfig<HexListProjectsParams, HexListProjects
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by status: PUBLISHED, DRAFT, or ALL',
|
||||
},
|
||||
includeComponents: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include components in results',
|
||||
},
|
||||
includeTrashed: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Include trashed projects in results',
|
||||
},
|
||||
creatorEmail: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by creator email',
|
||||
},
|
||||
ownerEmail: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by owner email',
|
||||
},
|
||||
collectionId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by collection UUID',
|
||||
},
|
||||
categories: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON array of category names to filter by (e.g., ["Marketing", "Finance"])',
|
||||
},
|
||||
sortBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Sort by field: CREATED_AT, LAST_EDITED_AT, or LAST_PUBLISHED_AT',
|
||||
},
|
||||
sortDirection: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Sort direction: ASC or DESC',
|
||||
},
|
||||
after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results after this value',
|
||||
},
|
||||
before: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results before this value',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -39,7 +99,33 @@ export const listProjectsTool: ToolConfig<HexListProjectsParams, HexListProjects
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params.limit) searchParams.set('limit', String(params.limit))
|
||||
if (params.includeArchived) searchParams.set('includeArchived', 'true')
|
||||
if (params.includeComponents) searchParams.set('includeComponents', 'true')
|
||||
if (params.includeTrashed) searchParams.set('includeTrashed', 'true')
|
||||
if (params.statusFilter) searchParams.append('statuses[]', params.statusFilter)
|
||||
if (params.creatorEmail) searchParams.set('creatorEmail', params.creatorEmail)
|
||||
if (params.ownerEmail) searchParams.set('ownerEmail', params.ownerEmail)
|
||||
if (params.collectionId) searchParams.set('collectionId', params.collectionId.trim())
|
||||
if (params.categories) {
|
||||
let categories: unknown
|
||||
try {
|
||||
categories =
|
||||
typeof params.categories === 'string'
|
||||
? JSON.parse(params.categories)
|
||||
: params.categories
|
||||
} catch {
|
||||
throw new Error('categories must be a valid JSON array of category name strings')
|
||||
}
|
||||
if (!Array.isArray(categories) || !categories.every((c) => typeof c === 'string')) {
|
||||
throw new Error('categories must be a valid JSON array of category name strings')
|
||||
}
|
||||
for (const category of categories) {
|
||||
searchParams.append('categories[]', category)
|
||||
}
|
||||
}
|
||||
if (params.sortBy) searchParams.set('sortBy', params.sortBy)
|
||||
if (params.sortDirection) searchParams.set('sortDirection', params.sortDirection)
|
||||
if (params.after) searchParams.set('after', params.after)
|
||||
if (params.before) searchParams.set('before', params.before)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/projects${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
@@ -80,6 +166,8 @@ export const listProjectsTool: ToolConfig<HexListProjectsParams, HexListProjects
|
||||
trashedAt: (p.trashedAt as string) ?? null,
|
||||
})),
|
||||
total: projects.length,
|
||||
after: data.pagination?.after ?? null,
|
||||
before: data.pagination?.before ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -134,5 +222,11 @@ export const listProjectsTool: ToolConfig<HexListProjectsParams, HexListProjects
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of projects returned' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results', optional: true },
|
||||
before: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -38,6 +38,24 @@ export const listUsersTool: ToolConfig<HexListUsersParams, HexListUsersResponse>
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter users by group UUID',
|
||||
},
|
||||
userIds: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated list of user UUIDs to filter by',
|
||||
},
|
||||
after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results after this value',
|
||||
},
|
||||
before: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Cursor to fetch the page of results before this value',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
@@ -47,6 +65,9 @@ export const listUsersTool: ToolConfig<HexListUsersParams, HexListUsersResponse>
|
||||
if (params.sortBy) searchParams.set('sortBy', params.sortBy)
|
||||
if (params.sortDirection) searchParams.set('sortDirection', params.sortDirection)
|
||||
if (params.groupId) searchParams.set('groupId', params.groupId)
|
||||
if (params.userIds) searchParams.set('userIds', params.userIds)
|
||||
if (params.after) searchParams.set('after', params.after)
|
||||
if (params.before) searchParams.set('before', params.before)
|
||||
const qs = searchParams.toString()
|
||||
return `https://app.hex.tech/api/v1/users${qs ? `?${qs}` : ''}`
|
||||
},
|
||||
@@ -69,8 +90,11 @@ export const listUsersTool: ToolConfig<HexListUsersParams, HexListUsersResponse>
|
||||
name: (u.name as string) ?? null,
|
||||
email: (u.email as string) ?? null,
|
||||
role: (u.role as string) ?? null,
|
||||
lastLoginDate: (u.lastLoginDate as string) ?? null,
|
||||
})),
|
||||
total: users.length,
|
||||
after: data.pagination?.after ?? null,
|
||||
before: data.pagination?.before ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -90,9 +114,20 @@ export const listUsersTool: ToolConfig<HexListUsersParams, HexListUsersResponse>
|
||||
description:
|
||||
'User role (ADMIN, MANAGER, EDITOR, EXPLORER, MEMBER, GUEST, EMBEDDED_USER, ANONYMOUS)',
|
||||
},
|
||||
lastLoginDate: {
|
||||
type: 'string',
|
||||
description: 'Last login timestamp',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
total: { type: 'number', description: 'Total number of users returned' },
|
||||
after: { type: 'string', description: 'Cursor for the next page of results', optional: true },
|
||||
before: {
|
||||
type: 'string',
|
||||
description: 'Cursor for the previous page of results',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -52,10 +52,23 @@ export const runProjectTool: ToolConfig<HexRunProjectParams, HexRunProjectRespon
|
||||
visibility: 'user-only',
|
||||
description: 'If true, use cached SQL results instead of re-running queries',
|
||||
},
|
||||
viewId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional SavedView ID to use for the project run',
|
||||
},
|
||||
notifications: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'JSON array of notification details to deliver once the run completes (e.g., [{"type": "FAILURE", "slackChannelIds": ["C0123456789"], "userIds": [], "groupIds": [], "includeSuccessScreenshot": false}]). type is ALL, SUCCESS, or FAILURE.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}/runs`,
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
@@ -65,10 +78,14 @@ export const runProjectTool: ToolConfig<HexRunProjectParams, HexRunProjectRespon
|
||||
const body: Record<string, unknown> = {}
|
||||
|
||||
if (params.inputParams) {
|
||||
body.inputParams =
|
||||
typeof params.inputParams === 'string'
|
||||
? JSON.parse(params.inputParams)
|
||||
: params.inputParams
|
||||
try {
|
||||
body.inputParams =
|
||||
typeof params.inputParams === 'string'
|
||||
? JSON.parse(params.inputParams)
|
||||
: params.inputParams
|
||||
} catch {
|
||||
throw new Error('inputParams must be valid JSON')
|
||||
}
|
||||
}
|
||||
if (params.dryRun !== undefined) body.dryRun = params.dryRun
|
||||
if (params.updateCache !== undefined) body.updateCache = params.updateCache
|
||||
@@ -76,6 +93,22 @@ export const runProjectTool: ToolConfig<HexRunProjectParams, HexRunProjectRespon
|
||||
body.updatePublishedResults = params.updatePublishedResults
|
||||
if (params.useCachedSqlResults !== undefined)
|
||||
body.useCachedSqlResults = params.useCachedSqlResults
|
||||
if (params.viewId) body.viewId = params.viewId.trim()
|
||||
if (params.notifications) {
|
||||
let notifications: unknown
|
||||
try {
|
||||
notifications =
|
||||
typeof params.notifications === 'string'
|
||||
? JSON.parse(params.notifications)
|
||||
: params.notifications
|
||||
} catch {
|
||||
throw new Error('notifications must be a valid JSON array')
|
||||
}
|
||||
if (!Array.isArray(notifications)) {
|
||||
throw new Error('notifications must be a valid JSON array')
|
||||
}
|
||||
body.notifications = notifications
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
|
||||
@@ -104,7 +104,17 @@ export interface HexListProjectsParams {
|
||||
apiKey: string
|
||||
limit?: number
|
||||
includeArchived?: boolean
|
||||
includeComponents?: boolean
|
||||
includeTrashed?: boolean
|
||||
statusFilter?: string
|
||||
creatorEmail?: string
|
||||
ownerEmail?: string
|
||||
collectionId?: string
|
||||
categories?: string
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
after?: string
|
||||
before?: string
|
||||
}
|
||||
|
||||
export interface HexListProjectsResponse extends ToolResponse {
|
||||
@@ -125,6 +135,8 @@ export interface HexListProjectsResponse extends ToolResponse {
|
||||
trashedAt: string | null
|
||||
}>
|
||||
total: number
|
||||
after: string | null
|
||||
before: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +171,8 @@ export interface HexRunProjectParams {
|
||||
updateCache?: boolean
|
||||
updatePublishedResults?: boolean
|
||||
useCachedSqlResults?: boolean
|
||||
viewId?: string
|
||||
notifications?: string
|
||||
}
|
||||
|
||||
export interface HexRunProjectResponse extends ToolResponse {
|
||||
@@ -212,6 +226,7 @@ export interface HexGetProjectRunsParams {
|
||||
limit?: number
|
||||
offset?: number
|
||||
statusFilter?: string
|
||||
runTriggerFilter?: string
|
||||
}
|
||||
|
||||
export interface HexGetProjectRunsResponse extends ToolResponse {
|
||||
@@ -229,6 +244,8 @@ export interface HexGetProjectRunsResponse extends ToolResponse {
|
||||
}>
|
||||
total: number
|
||||
traceId: string | null
|
||||
nextPage: string | null
|
||||
previousPage: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +279,9 @@ export interface HexListUsersParams {
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
groupId?: string
|
||||
userIds?: string
|
||||
after?: string
|
||||
before?: string
|
||||
}
|
||||
|
||||
export interface HexListUsersResponse extends ToolResponse {
|
||||
@@ -271,8 +291,11 @@ export interface HexListUsersResponse extends ToolResponse {
|
||||
name: string
|
||||
email: string
|
||||
role: string
|
||||
lastLoginDate: string | null
|
||||
}>
|
||||
total: number
|
||||
after: string | null
|
||||
before: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +303,8 @@ export interface HexListCollectionsParams {
|
||||
apiKey: string
|
||||
limit?: number
|
||||
sortBy?: string
|
||||
after?: string
|
||||
before?: string
|
||||
}
|
||||
|
||||
export interface HexListCollectionsResponse extends ToolResponse {
|
||||
@@ -291,6 +316,8 @@ export interface HexListCollectionsResponse extends ToolResponse {
|
||||
creator: { email: string; id: string } | null
|
||||
}>
|
||||
total: number
|
||||
after: string | null
|
||||
before: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +326,8 @@ export interface HexListDataConnectionsParams {
|
||||
limit?: number
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
after?: string
|
||||
before?: string
|
||||
}
|
||||
|
||||
export interface HexListDataConnectionsResponse extends ToolResponse {
|
||||
@@ -313,6 +342,8 @@ export interface HexListDataConnectionsResponse extends ToolResponse {
|
||||
allowWritebackCells: boolean | null
|
||||
}>
|
||||
total: number
|
||||
after: string | null
|
||||
before: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,6 +369,8 @@ export interface HexListGroupsParams {
|
||||
limit?: number
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
after?: string
|
||||
before?: string
|
||||
}
|
||||
|
||||
export interface HexListGroupsResponse extends ToolResponse {
|
||||
@@ -348,6 +381,8 @@ export interface HexListGroupsResponse extends ToolResponse {
|
||||
createdAt: string | null
|
||||
}>
|
||||
total: number
|
||||
after: string | null
|
||||
before: string | null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,6 +445,76 @@ export interface HexCreateCollectionResponse extends ToolResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface HexUpdateCollectionParams {
|
||||
apiKey: string
|
||||
collectionId: string
|
||||
name?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface HexUpdateCollectionResponse extends ToolResponse {
|
||||
output: {
|
||||
id: string
|
||||
name: string
|
||||
description: string | null
|
||||
creator: { email: string; id: string } | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface HexCreateGroupParams {
|
||||
apiKey: string
|
||||
name: string
|
||||
memberUserIds?: string
|
||||
}
|
||||
|
||||
export interface HexCreateGroupResponse extends ToolResponse {
|
||||
output: {
|
||||
id: string
|
||||
name: string
|
||||
createdAt: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface HexUpdateGroupParams {
|
||||
apiKey: string
|
||||
groupId: string
|
||||
name?: string
|
||||
addUserIds?: string
|
||||
removeUserIds?: string
|
||||
}
|
||||
|
||||
export interface HexUpdateGroupResponse extends ToolResponse {
|
||||
output: {
|
||||
id: string
|
||||
name: string
|
||||
createdAt: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface HexDeleteGroupParams {
|
||||
apiKey: string
|
||||
groupId: string
|
||||
}
|
||||
|
||||
export interface HexDeleteGroupResponse extends ToolResponse {
|
||||
output: {
|
||||
success: boolean
|
||||
groupId: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface HexDeactivateUserParams {
|
||||
apiKey: string
|
||||
userId: string
|
||||
}
|
||||
|
||||
export interface HexDeactivateUserResponse extends ToolResponse {
|
||||
output: {
|
||||
success: boolean
|
||||
userId: string
|
||||
}
|
||||
}
|
||||
|
||||
export type HexResponse =
|
||||
| HexListProjectsResponse
|
||||
| HexGetProjectResponse
|
||||
@@ -427,3 +532,8 @@ export type HexResponse =
|
||||
| HexGetDataConnectionResponse
|
||||
| HexGetCollectionResponse
|
||||
| HexCreateCollectionResponse
|
||||
| HexUpdateCollectionResponse
|
||||
| HexCreateGroupResponse
|
||||
| HexUpdateGroupResponse
|
||||
| HexDeleteGroupResponse
|
||||
| HexDeactivateUserResponse
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import type { HexUpdateCollectionParams, HexUpdateCollectionResponse } from '@/tools/hex/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const updateCollectionTool: ToolConfig<
|
||||
HexUpdateCollectionParams,
|
||||
HexUpdateCollectionResponse
|
||||
> = {
|
||||
id: 'hex_update_collection',
|
||||
name: 'Hex Update Collection',
|
||||
description: 'Update the name or description of an existing Hex collection.',
|
||||
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 to update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New name for the collection',
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New description for the collection',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name
|
||||
if (params.description !== undefined) 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: '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' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { HexUpdateGroupParams, HexUpdateGroupResponse } from '@/tools/hex/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const updateGroupTool: ToolConfig<HexUpdateGroupParams, HexUpdateGroupResponse> = {
|
||||
id: 'hex_update_group',
|
||||
name: 'Hex Update Group',
|
||||
description: 'Rename a Hex group or add/remove members from it.',
|
||||
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 to update',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New name for the group',
|
||||
},
|
||||
addUserIds: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON array of user UUIDs to add to the group (e.g., ["uuid1", "uuid2"])',
|
||||
},
|
||||
removeUserIds: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON array of user UUIDs to remove from the group (e.g., ["uuid1", "uuid2"])',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name
|
||||
|
||||
const parseIds = (value: unknown): string[] => {
|
||||
let parsed: unknown
|
||||
try {
|
||||
parsed = typeof value === 'string' ? JSON.parse(value) : value
|
||||
} catch {
|
||||
throw new Error(
|
||||
'addUserIds/removeUserIds must be a valid JSON array of user UUID strings'
|
||||
)
|
||||
}
|
||||
if (!Array.isArray(parsed) || !parsed.every((id) => typeof id === 'string')) {
|
||||
throw new Error(
|
||||
'addUserIds/removeUserIds must be a valid JSON array of user UUID strings'
|
||||
)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
if (params.addUserIds || params.removeUserIds) {
|
||||
const members: Record<string, unknown> = {}
|
||||
if (params.addUserIds) {
|
||||
members.add = { users: parseIds(params.addUserIds).map((id) => ({ id: id.trim() })) }
|
||||
}
|
||||
if (params.removeUserIds) {
|
||||
members.remove = {
|
||||
users: parseIds(params.removeUserIds).map((id) => ({ id: id.trim() })),
|
||||
}
|
||||
}
|
||||
body.members = members
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
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' },
|
||||
},
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export const updateProjectTool: ToolConfig<HexUpdateProjectParams, HexUpdateProj
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}`,
|
||||
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
|
||||
@@ -1556,6 +1556,9 @@ import { guardrailsValidateTool } from '@/tools/guardrails'
|
||||
import {
|
||||
hexCancelRunTool,
|
||||
hexCreateCollectionTool,
|
||||
hexCreateGroupTool,
|
||||
hexDeactivateUserTool,
|
||||
hexDeleteGroupTool,
|
||||
hexGetCollectionTool,
|
||||
hexGetDataConnectionTool,
|
||||
hexGetGroupTool,
|
||||
@@ -1569,6 +1572,8 @@ import {
|
||||
hexListProjectsTool,
|
||||
hexListUsersTool,
|
||||
hexRunProjectTool,
|
||||
hexUpdateCollectionTool,
|
||||
hexUpdateGroupTool,
|
||||
hexUpdateProjectTool,
|
||||
} from '@/tools/hex'
|
||||
import { httpRequestTool, webhookRequestTool } from '@/tools/http'
|
||||
@@ -4638,6 +4643,9 @@ export const tools: Record<string, ToolConfig> = {
|
||||
guardrails_validate: guardrailsValidateTool,
|
||||
hex_cancel_run: hexCancelRunTool,
|
||||
hex_create_collection: hexCreateCollectionTool,
|
||||
hex_create_group: hexCreateGroupTool,
|
||||
hex_deactivate_user: hexDeactivateUserTool,
|
||||
hex_delete_group: hexDeleteGroupTool,
|
||||
hex_get_collection: hexGetCollectionTool,
|
||||
hex_get_data_connection: hexGetDataConnectionTool,
|
||||
hex_get_group: hexGetGroupTool,
|
||||
@@ -4651,6 +4659,8 @@ export const tools: Record<string, ToolConfig> = {
|
||||
hex_list_projects: hexListProjectsTool,
|
||||
hex_list_users: hexListUsersTool,
|
||||
hex_run_project: hexRunProjectTool,
|
||||
hex_update_collection: hexUpdateCollectionTool,
|
||||
hex_update_group: hexUpdateGroupTool,
|
||||
hex_update_project: hexUpdateProjectTool,
|
||||
instantly_activate_campaign: instantlyActivateCampaignTool,
|
||||
instantly_create_campaign: instantlyCreateCampaignTool,
|
||||
|
||||
Reference in New Issue
Block a user