Skip to content

Commit c93dd74

Browse files
committed
Better tool calls
1 parent 75a7dbc commit c93dd74

19 files changed

Lines changed: 456 additions & 47 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel-new/components/copilot/components/inline-tool-call/inline-tool-call.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ const ACTION_VERBS = [
5252
'Editing',
5353
'Edited',
5454
'Running',
55+
'Ran',
5556
'Designing',
5657
'Designed',
58+
'Searching',
59+
'Searched',
5760
'Summarizing',
5861
'Summarized',
5962
'Marking',
@@ -70,6 +73,11 @@ const ACTION_VERBS = [
7073
'Evaluating',
7174
'Evaluated',
7275
'Finished',
76+
'Setting',
77+
'Set',
78+
'Applied',
79+
'Applying',
80+
'Rejected',
7381
] as const
7482

7583
/**

apps/sim/lib/copilot/tools/client/base-tool.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,28 @@ export interface ClientToolDisplay {
2323
icon: LucideIcon
2424
}
2525

26+
/**
27+
* Function to generate dynamic display text based on tool parameters and state
28+
* @param params - The tool call parameters
29+
* @param state - The current tool call state
30+
* @returns The dynamic text to display, or undefined to use the default text
31+
*/
32+
export type DynamicTextFormatter = (
33+
params: Record<string, any>,
34+
state: ClientToolCallState
35+
) => string | undefined
36+
2637
export interface BaseClientToolMetadata {
2738
displayNames: Partial<Record<ClientToolCallState, ClientToolDisplay>>
2839
interrupt?: {
2940
accept: ClientToolDisplay
3041
reject: ClientToolDisplay
3142
}
43+
/**
44+
* Optional function to generate dynamic display text based on parameters
45+
* If provided, this will override the default text in displayNames
46+
*/
47+
getDynamicText?: DynamicTextFormatter
3248
}
3349

3450
export class BaseClientTool {

apps/sim/lib/copilot/tools/client/blocks/get-blocks-metadata.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,43 @@ export class GetBlocksMetadataClientTool extends BaseClientTool {
2424

2525
static readonly metadata: BaseClientToolMetadata = {
2626
displayNames: {
27-
[ClientToolCallState.generating]: { text: 'Evaluating block choices', icon: Loader2 },
28-
[ClientToolCallState.pending]: { text: 'Evaluating block choices', icon: Loader2 },
29-
[ClientToolCallState.executing]: { text: 'Evaluating block choices', icon: Loader2 },
30-
[ClientToolCallState.success]: { text: 'Evaluated block choices', icon: ListFilter },
31-
[ClientToolCallState.error]: { text: 'Failed to evaluate block choices', icon: XCircle },
32-
[ClientToolCallState.aborted]: { text: 'Aborted evaluating block choices', icon: XCircle },
27+
[ClientToolCallState.generating]: { text: 'Searching block choices', icon: Loader2 },
28+
[ClientToolCallState.pending]: { text: 'Searching block choices', icon: Loader2 },
29+
[ClientToolCallState.executing]: { text: 'Searching block choices', icon: Loader2 },
30+
[ClientToolCallState.success]: { text: 'Searched block choices', icon: ListFilter },
31+
[ClientToolCallState.error]: { text: 'Failed to search block choices', icon: XCircle },
32+
[ClientToolCallState.aborted]: { text: 'Aborted searching block choices', icon: XCircle },
3333
[ClientToolCallState.rejected]: {
34-
text: 'Skipped evaluating block choices',
34+
text: 'Skipped searching block choices',
3535
icon: MinusCircle,
3636
},
3737
},
38+
getDynamicText: (params, state) => {
39+
if (params?.blockIds && Array.isArray(params.blockIds) && params.blockIds.length > 0) {
40+
const blockList = params.blockIds
41+
.slice(0, 3)
42+
.map((blockId) => blockId.replace(/_/g, ' '))
43+
.join(', ')
44+
const more = params.blockIds.length > 3 ? '...' : ''
45+
const blocks = `${blockList}${more}`
46+
47+
switch (state) {
48+
case ClientToolCallState.success:
49+
return `Searched ${blocks}`
50+
case ClientToolCallState.executing:
51+
case ClientToolCallState.generating:
52+
case ClientToolCallState.pending:
53+
return `Searching ${blocks}`
54+
case ClientToolCallState.error:
55+
return `Failed to search ${blocks}`
56+
case ClientToolCallState.aborted:
57+
return `Aborted searching ${blocks}`
58+
case ClientToolCallState.rejected:
59+
return `Skipped searching ${blocks}`
60+
}
61+
}
62+
return undefined
63+
},
3864
}
3965

4066
async execute(args?: GetBlocksMetadataArgs): Promise<void> {

apps/sim/lib/copilot/tools/client/examples/get-examples-rag.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,28 @@ export class GetExamplesRagClientTool extends BaseClientTool {
2323
[ClientToolCallState.rejected]: { text: 'Skipped getting examples', icon: MinusCircle },
2424
},
2525
interrupt: undefined,
26+
getDynamicText: (params, state) => {
27+
if (params?.query && typeof params.query === 'string') {
28+
const query = params.query
29+
const truncated = query.length > 40 ? `${query.slice(0, 40)}...` : query
30+
31+
switch (state) {
32+
case ClientToolCallState.success:
33+
return `Found examples for ${truncated}`
34+
case ClientToolCallState.executing:
35+
case ClientToolCallState.generating:
36+
case ClientToolCallState.pending:
37+
return `Searching examples for ${truncated}`
38+
case ClientToolCallState.error:
39+
return `Failed to find examples for ${truncated}`
40+
case ClientToolCallState.aborted:
41+
return `Aborted searching examples for ${truncated}`
42+
case ClientToolCallState.rejected:
43+
return `Skipped searching examples for ${truncated}`
44+
}
45+
}
46+
return undefined
47+
},
2648
}
2749

2850
async execute(): Promise<void> {

apps/sim/lib/copilot/tools/client/examples/get-operations-examples.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,28 @@ export class GetOperationsExamplesClientTool extends BaseClientTool {
2929
},
3030
},
3131
interrupt: undefined,
32+
getDynamicText: (params, state) => {
33+
if (params?.query && typeof params.query === 'string') {
34+
const query = params.query
35+
const truncated = query.length > 40 ? `${query.slice(0, 40)}...` : query
36+
37+
switch (state) {
38+
case ClientToolCallState.success:
39+
return `Designed ${truncated}`
40+
case ClientToolCallState.executing:
41+
case ClientToolCallState.generating:
42+
case ClientToolCallState.pending:
43+
return `Designing ${truncated}`
44+
case ClientToolCallState.error:
45+
return `Failed to design ${truncated}`
46+
case ClientToolCallState.aborted:
47+
return `Aborted designing ${truncated}`
48+
case ClientToolCallState.rejected:
49+
return `Skipped designing ${truncated}`
50+
}
51+
}
52+
return undefined
53+
},
3254
}
3355

3456
async execute(): Promise<void> {

apps/sim/lib/copilot/tools/client/gdrive/list-files.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ export class ListGDriveFilesClientTool extends BaseClientTool {
3232
[ClientToolCallState.error]: { text: 'Failed to list GDrive files', icon: XCircle },
3333
[ClientToolCallState.rejected]: { text: 'Skipped listing GDrive files', icon: MinusCircle },
3434
},
35+
getDynamicText: (params, state) => {
36+
const searchQuery = params?.search_query || params?.searchQuery
37+
if (searchQuery && typeof searchQuery === 'string') {
38+
const query = searchQuery
39+
const truncated = query.length > 40 ? `${query.slice(0, 40)}...` : query
40+
41+
switch (state) {
42+
case ClientToolCallState.success:
43+
return `Listed files matching ${truncated}`
44+
case ClientToolCallState.executing:
45+
case ClientToolCallState.generating:
46+
case ClientToolCallState.pending:
47+
return `Listing files matching ${truncated}`
48+
case ClientToolCallState.error:
49+
return `Failed to list files matching ${truncated}`
50+
case ClientToolCallState.rejected:
51+
return `Skipped listing files matching ${truncated}`
52+
}
53+
}
54+
return undefined
55+
},
3556
}
3657

3758
async execute(args?: ListGDriveFilesArgs): Promise<void> {

apps/sim/lib/copilot/tools/client/gdrive/read-file.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ export class ReadGDriveFileClientTool extends BaseClientTool {
3434
icon: MinusCircle,
3535
},
3636
},
37+
getDynamicText: (params, state) => {
38+
if (params?.fileId && typeof params.fileId === 'string') {
39+
const fileId = params.fileId
40+
const fileType = params?.type ? ` (${params.type})` : ''
41+
42+
switch (state) {
43+
case ClientToolCallState.success:
44+
return `Read file ${fileId}${fileType}`
45+
case ClientToolCallState.executing:
46+
case ClientToolCallState.generating:
47+
case ClientToolCallState.pending:
48+
return `Reading file ${fileId}${fileType}`
49+
case ClientToolCallState.error:
50+
return `Failed to read file ${fileId}${fileType}`
51+
case ClientToolCallState.aborted:
52+
return `Aborted reading file ${fileId}${fileType}`
53+
case ClientToolCallState.rejected:
54+
return `Skipped reading file ${fileId}${fileType}`
55+
}
56+
}
57+
return undefined
58+
},
3759
}
3860

3961
async execute(args?: ReadGDriveFileArgs): Promise<void> {

apps/sim/lib/copilot/tools/client/other/make-api-request.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,44 @@ export class MakeApiRequestClientTool extends BaseClientTool {
3636
accept: { text: 'Execute', icon: Globe2 },
3737
reject: { text: 'Skip', icon: MinusCircle },
3838
},
39+
getDynamicText: (params, state) => {
40+
if (params?.url && typeof params.url === 'string') {
41+
const method = params.method || 'GET'
42+
let url = params.url
43+
44+
// Extract domain from URL for cleaner display
45+
try {
46+
const urlObj = new URL(url)
47+
url = urlObj.hostname + urlObj.pathname
48+
if (url.length > 40) {
49+
url = url.slice(0, 40) + '...'
50+
}
51+
} catch {
52+
// If URL parsing fails, just truncate
53+
if (url.length > 40) {
54+
url = url.slice(0, 40) + '...'
55+
}
56+
}
57+
58+
switch (state) {
59+
case ClientToolCallState.success:
60+
return `${method} ${url} complete`
61+
case ClientToolCallState.executing:
62+
return `${method} ${url}`
63+
case ClientToolCallState.generating:
64+
return `Preparing ${method} ${url}`
65+
case ClientToolCallState.pending:
66+
return `Review ${method} ${url}`
67+
case ClientToolCallState.error:
68+
return `Failed ${method} ${url}`
69+
case ClientToolCallState.rejected:
70+
return `Skipped ${method} ${url}`
71+
case ClientToolCallState.aborted:
72+
return `Aborted ${method} ${url}`
73+
}
74+
}
75+
return undefined
76+
},
3977
}
4078

4179
async handleReject(): Promise<void> {

apps/sim/lib/copilot/tools/client/other/search-documentation.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,28 @@ export class SearchDocumentationClientTool extends BaseClientTool {
3030
[ClientToolCallState.aborted]: { text: 'Aborted documentation search', icon: XCircle },
3131
[ClientToolCallState.rejected]: { text: 'Skipped documentation search', icon: MinusCircle },
3232
},
33+
getDynamicText: (params, state) => {
34+
if (params?.query && typeof params.query === 'string') {
35+
const query = params.query
36+
const truncated = query.length > 50 ? `${query.slice(0, 50)}...` : query
37+
38+
switch (state) {
39+
case ClientToolCallState.success:
40+
return `Searched docs for ${truncated}`
41+
case ClientToolCallState.executing:
42+
case ClientToolCallState.generating:
43+
case ClientToolCallState.pending:
44+
return `Searching docs for ${truncated}`
45+
case ClientToolCallState.error:
46+
return `Failed to search docs for ${truncated}`
47+
case ClientToolCallState.aborted:
48+
return `Aborted searching docs for ${truncated}`
49+
case ClientToolCallState.rejected:
50+
return `Skipped searching docs for ${truncated}`
51+
}
52+
}
53+
return undefined
54+
},
3355
}
3456

3557
async execute(args?: SearchDocumentationArgs): Promise<void> {

apps/sim/lib/copilot/tools/client/other/search-online.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,28 @@ export class SearchOnlineClientTool extends BaseClientTool {
3232
[ClientToolCallState.rejected]: { text: 'Skipped online search', icon: MinusCircle },
3333
[ClientToolCallState.aborted]: { text: 'Aborted online search', icon: XCircle },
3434
},
35+
getDynamicText: (params, state) => {
36+
if (params?.query && typeof params.query === 'string') {
37+
const query = params.query
38+
const truncated = query.length > 50 ? `${query.slice(0, 50)}...` : query
39+
40+
switch (state) {
41+
case ClientToolCallState.success:
42+
return `Searched online for ${truncated}`
43+
case ClientToolCallState.executing:
44+
case ClientToolCallState.generating:
45+
case ClientToolCallState.pending:
46+
return `Searching online for ${truncated}`
47+
case ClientToolCallState.error:
48+
return `Failed to search online for ${truncated}`
49+
case ClientToolCallState.aborted:
50+
return `Aborted searching online for ${truncated}`
51+
case ClientToolCallState.rejected:
52+
return `Skipped searching online for ${truncated}`
53+
}
54+
}
55+
return undefined
56+
},
3557
}
3658

3759
async execute(args?: SearchOnlineArgs): Promise<void> {

0 commit comments

Comments
 (0)