Skip to content

Commit 736e765

Browse files
committed
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
1 parent 62ef96f commit 736e765

23 files changed

Lines changed: 841 additions & 22 deletions

apps/sim/blocks/blocks/hex.ts

Lines changed: 226 additions & 12 deletions
Large diffs are not rendered by default.

apps/sim/tools/hex/cancel_run.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export const cancelRunTool: ToolConfig<HexCancelRunParams, HexCancelRunResponse>
3030

3131
request: {
3232
url: (params) =>
33-
`https://app.hex.tech/api/v1/projects/${params.projectId}/runs/${params.runId}`,
33+
`https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs/${params.runId.trim()}`,
3434
method: 'DELETE',
3535
headers: (params) => ({
3636
Authorization: `Bearer ${params.apiKey}`,

apps/sim/tools/hex/create_group.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import type { HexCreateGroupParams, HexCreateGroupResponse } from '@/tools/hex/types'
2+
import type { ToolConfig } from '@/tools/types'
3+
4+
export const createGroupTool: ToolConfig<HexCreateGroupParams, HexCreateGroupResponse> = {
5+
id: 'hex_create_group',
6+
name: 'Hex Create Group',
7+
description: 'Create a new group in the Hex workspace, optionally with initial members.',
8+
version: '1.0.0',
9+
10+
params: {
11+
apiKey: {
12+
type: 'string',
13+
required: true,
14+
visibility: 'user-only',
15+
description: 'Hex API token (Personal or Workspace)',
16+
},
17+
name: {
18+
type: 'string',
19+
required: true,
20+
visibility: 'user-or-llm',
21+
description: 'Name for the new group',
22+
},
23+
memberUserIds: {
24+
type: 'json',
25+
required: false,
26+
visibility: 'user-or-llm',
27+
description:
28+
'JSON array of user UUIDs to add as initial group members (e.g., ["uuid1", "uuid2"])',
29+
},
30+
},
31+
32+
request: {
33+
url: 'https://app.hex.tech/api/v1/groups',
34+
method: 'POST',
35+
headers: (params) => ({
36+
Authorization: `Bearer ${params.apiKey}`,
37+
'Content-Type': 'application/json',
38+
}),
39+
body: (params) => {
40+
const body: Record<string, unknown> = { name: params.name }
41+
if (params.memberUserIds) {
42+
const userIds =
43+
typeof params.memberUserIds === 'string'
44+
? JSON.parse(params.memberUserIds)
45+
: params.memberUserIds
46+
body.members = { users: (userIds as string[]).map((id) => ({ id })) }
47+
}
48+
return body
49+
},
50+
},
51+
52+
transformResponse: async (response: Response) => {
53+
const data = await response.json()
54+
55+
return {
56+
success: true,
57+
output: {
58+
id: data.id ?? null,
59+
name: data.name ?? null,
60+
createdAt: data.createdAt ?? null,
61+
},
62+
}
63+
},
64+
65+
outputs: {
66+
id: { type: 'string', description: 'Newly created group UUID' },
67+
name: { type: 'string', description: 'Group name' },
68+
createdAt: { type: 'string', description: 'Creation timestamp' },
69+
},
70+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { HexDeactivateUserParams, HexDeactivateUserResponse } from '@/tools/hex/types'
2+
import type { ToolConfig } from '@/tools/types'
3+
4+
export const deactivateUserTool: ToolConfig<HexDeactivateUserParams, HexDeactivateUserResponse> = {
5+
id: 'hex_deactivate_user',
6+
name: 'Hex Deactivate User',
7+
description: 'Deactivate a user in the Hex workspace.',
8+
version: '1.0.0',
9+
10+
params: {
11+
apiKey: {
12+
type: 'string',
13+
required: true,
14+
visibility: 'user-only',
15+
description: 'Hex API token (Personal or Workspace)',
16+
},
17+
userId: {
18+
type: 'string',
19+
required: true,
20+
visibility: 'user-or-llm',
21+
description: 'The UUID of the user to deactivate',
22+
},
23+
},
24+
25+
request: {
26+
url: (params) => `https://app.hex.tech/api/v1/users/${params.userId.trim()}/deactivate`,
27+
method: 'POST',
28+
headers: (params) => ({
29+
Authorization: `Bearer ${params.apiKey}`,
30+
'Content-Type': 'application/json',
31+
}),
32+
},
33+
34+
transformResponse: async (response: Response, params) => {
35+
if (response.status === 204 || response.ok) {
36+
return {
37+
success: true,
38+
output: {
39+
success: true,
40+
userId: params?.userId ?? '',
41+
},
42+
}
43+
}
44+
45+
const data = await response.json().catch(() => ({}))
46+
return {
47+
success: false,
48+
output: {
49+
success: false,
50+
userId: params?.userId ?? '',
51+
},
52+
error: (data as Record<string, string>).message ?? 'Failed to deactivate user',
53+
}
54+
},
55+
56+
outputs: {
57+
success: { type: 'boolean', description: 'Whether the user was successfully deactivated' },
58+
userId: { type: 'string', description: 'User UUID that was deactivated' },
59+
},
60+
}

apps/sim/tools/hex/delete_group.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { HexDeleteGroupParams, HexDeleteGroupResponse } from '@/tools/hex/types'
2+
import type { ToolConfig } from '@/tools/types'
3+
4+
export const deleteGroupTool: ToolConfig<HexDeleteGroupParams, HexDeleteGroupResponse> = {
5+
id: 'hex_delete_group',
6+
name: 'Hex Delete Group',
7+
description: 'Delete a group from the Hex workspace.',
8+
version: '1.0.0',
9+
10+
params: {
11+
apiKey: {
12+
type: 'string',
13+
required: true,
14+
visibility: 'user-only',
15+
description: 'Hex API token (Personal or Workspace)',
16+
},
17+
groupId: {
18+
type: 'string',
19+
required: true,
20+
visibility: 'user-or-llm',
21+
description: 'The UUID of the group to delete',
22+
},
23+
},
24+
25+
request: {
26+
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId.trim()}`,
27+
method: 'DELETE',
28+
headers: (params) => ({
29+
Authorization: `Bearer ${params.apiKey}`,
30+
'Content-Type': 'application/json',
31+
}),
32+
},
33+
34+
transformResponse: async (response: Response, params) => {
35+
if (response.status === 204 || response.ok) {
36+
return {
37+
success: true,
38+
output: {
39+
success: true,
40+
groupId: params?.groupId ?? '',
41+
},
42+
}
43+
}
44+
45+
const data = await response.json().catch(() => ({}))
46+
return {
47+
success: false,
48+
output: {
49+
success: false,
50+
groupId: params?.groupId ?? '',
51+
},
52+
error: (data as Record<string, string>).message ?? 'Failed to delete group',
53+
}
54+
},
55+
56+
outputs: {
57+
success: { type: 'boolean', description: 'Whether the group was successfully deleted' },
58+
groupId: { type: 'string', description: 'Group UUID that was deleted' },
59+
},
60+
}

apps/sim/tools/hex/get_collection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const getCollectionTool: ToolConfig<HexGetCollectionParams, HexGetCollect
2323
},
2424

2525
request: {
26-
url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId}`,
26+
url: (params) => `https://app.hex.tech/api/v1/collections/${params.collectionId.trim()}`,
2727
method: 'GET',
2828
headers: (params) => ({
2929
Authorization: `Bearer ${params.apiKey}`,

apps/sim/tools/hex/get_data_connection.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export const getDataConnectionTool: ToolConfig<
2727
},
2828

2929
request: {
30-
url: (params) => `https://app.hex.tech/api/v1/data-connections/${params.dataConnectionId}`,
30+
url: (params) =>
31+
`https://app.hex.tech/api/v1/data-connections/${params.dataConnectionId.trim()}`,
3132
method: 'GET',
3233
headers: (params) => ({
3334
Authorization: `Bearer ${params.apiKey}`,

apps/sim/tools/hex/get_group.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const getGroupTool: ToolConfig<HexGetGroupParams, HexGetGroupResponse> =
2323
},
2424

2525
request: {
26-
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId}`,
26+
url: (params) => `https://app.hex.tech/api/v1/groups/${params.groupId.trim()}`,
2727
method: 'GET',
2828
headers: (params) => ({
2929
Authorization: `Bearer ${params.apiKey}`,

apps/sim/tools/hex/get_project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export const getProjectTool: ToolConfig<HexGetProjectParams, HexGetProjectRespon
2424
},
2525

2626
request: {
27-
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId}`,
27+
url: (params) => `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}`,
2828
method: 'GET',
2929
headers: (params) => ({
3030
Authorization: `Bearer ${params.apiKey}`,

apps/sim/tools/hex/get_project_runs.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
4040
description:
4141
'Filter by run status: PENDING, RUNNING, ERRORED, COMPLETED, KILLED, UNABLE_TO_ALLOCATE_KERNEL',
4242
},
43+
runTriggerFilter: {
44+
type: 'string',
45+
required: false,
46+
visibility: 'user-or-llm',
47+
description: 'Filter by how the run was triggered: ALL, API, SCHEDULED, or APP_REFRESH',
48+
},
4349
},
4450

4551
request: {
@@ -48,8 +54,9 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
4854
if (params.limit) searchParams.set('limit', String(params.limit))
4955
if (params.offset) searchParams.set('offset', String(params.offset))
5056
if (params.statusFilter) searchParams.set('statusFilter', params.statusFilter)
57+
if (params.runTriggerFilter) searchParams.set('runTriggerFilter', params.runTriggerFilter)
5158
const qs = searchParams.toString()
52-
return `https://app.hex.tech/api/v1/projects/${params.projectId}/runs${qs ? `?${qs}` : ''}`
59+
return `https://app.hex.tech/api/v1/projects/${params.projectId.trim()}/runs${qs ? `?${qs}` : ''}`
5360
},
5461
method: 'GET',
5562
headers: (params) => ({
@@ -78,6 +85,8 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
7885
})),
7986
total: runs.length,
8087
traceId: data.traceId ?? null,
88+
nextPage: data.nextPage ?? null,
89+
previousPage: data.previousPage ?? null,
8190
},
8291
}
8392
},
@@ -111,5 +120,11 @@ export const getProjectRunsTool: ToolConfig<HexGetProjectRunsParams, HexGetProje
111120
},
112121
total: { type: 'number', description: 'Total number of runs returned' },
113122
traceId: { type: 'string', description: 'Top-level trace ID', optional: true },
123+
nextPage: { type: 'string', description: 'Cursor for the next page of runs', optional: true },
124+
previousPage: {
125+
type: 'string',
126+
description: 'Cursor for the previous page of runs',
127+
optional: true,
128+
},
114129
},
115130
}

0 commit comments

Comments
 (0)