Skip to content

Commit 3bc4997

Browse files
committed
improvement(superagent): nuke superagent
1 parent 31aca74 commit 3bc4997

10 files changed

Lines changed: 346 additions & 55 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.test.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/**
22
* @vitest-environment node
33
*/
4-
import type { ReactNode } from 'react'
4+
import type { ReactNode, SVGProps } from 'react'
55
import { renderToStaticMarkup } from 'react-dom/server'
66
import { describe, expect, it, vi } from 'vitest'
7+
import { getBlockByToolName } from '@/blocks/registry'
78
import { ToolCallItem } from './tool-call-item'
89

910
vi.mock('@/components/ui', () => ({
@@ -39,4 +40,21 @@ describe('ToolCallItem', () => {
3940
expect(markup).toContain('Wrote brief.md')
4041
expect(markup).not.toContain('Writing brief.md')
4142
})
43+
44+
it('renders the owning integration icon for a resolved integration operation', () => {
45+
vi.mocked(getBlockByToolName).mockReturnValueOnce({
46+
name: 'Gmail',
47+
icon: (props: SVGProps<SVGSVGElement>) => <svg {...props} data-testid='gmail-icon' />,
48+
} as ReturnType<typeof getBlockByToolName>)
49+
const markup = renderToStaticMarkup(
50+
<ToolCallItem
51+
toolName='gmail_read_v2'
52+
displayTitle='Gmail: Searching for invoice emails'
53+
status='executing'
54+
/>
55+
)
56+
57+
expect(markup).toContain('<svg')
58+
expect(markup).toContain('Gmail: Searching for invoice emails')
59+
})
4260
})

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-call-item.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Read as ReadTool, WorkspaceFile } from '@/lib/copilot/generated/tool-ca
44
import { getReadTargetBlock } from '@/lib/copilot/tools/client/read-block'
55
import { getToolCompletedTitle } from '@/lib/copilot/tools/tool-display'
66
import { getBareIconStyle } from '@/blocks/icon-color'
7+
import { getBlockByToolName } from '@/blocks/registry'
78
import type { ToolCallStatus } from '../../../../types'
89
import { resolveToolDisplayState } from '../../utils'
910

@@ -88,7 +89,7 @@ export function ToolCallItem({
8889
? (getToolCompletedTitle(liveTitle) ?? liveTitle)
8990
: liveTitle
9091

91-
const BlockIcon = readBlock?.icon
92+
const BlockIcon = (readBlock ?? getBlockByToolName(toolName))?.icon
9293

9394
return (
9495
<div className='flex items-center gap-[6px] pl-6'>

apps/sim/lib/copilot/chat/payload.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ vi.mock('@/tools/registry', () => ({
3333
id: 'gmail_send',
3434
name: 'Gmail Send',
3535
description: 'Send emails using Gmail',
36+
outputs: { messageId: { type: 'string', description: 'Sent message ID' } },
37+
oauth: { required: true, provider: 'google-email' },
3638
},
3739
brandfetch_search: {
3840
id: 'brandfetch_search',
@@ -67,7 +69,13 @@ vi.mock('@/lib/copilot/integration-tools', () => ({
6769
getExposedIntegrationTools: vi.fn(() => [
6870
{
6971
toolId: 'gmail_send',
70-
config: { id: 'gmail_send', name: 'Gmail Send', description: 'Send emails using Gmail' },
72+
config: {
73+
id: 'gmail_send',
74+
name: 'Gmail Send',
75+
description: 'Send emails using Gmail',
76+
outputs: { messageId: { type: 'string', description: 'Sent message ID' } },
77+
oauth: { required: true, provider: 'google-email' },
78+
},
7179
service: 'gmail',
7280
operation: 'send',
7381
},
@@ -154,6 +162,22 @@ describe('buildIntegrationToolSchemas', () => {
154162
expect(runTool?.executeLocally).toBe(true)
155163
})
156164

165+
it('preserves operation, outputs, and OAuth discovery metadata', async () => {
166+
mockGetHighestPrioritySubscription.mockResolvedValue({ plan: 'pro', status: 'active' })
167+
168+
const toolSchemas = await buildIntegrationToolSchemas('user-metadata')
169+
const gmailTool = toolSchemas.find((tool) => tool.name === 'gmail_send')
170+
171+
expect(gmailTool).toEqual(
172+
expect.objectContaining({
173+
service: 'gmail',
174+
operation: 'send',
175+
outputs: { messageId: { type: 'string', description: 'Sent message ID' } },
176+
oauth: { required: true, provider: 'google-email' },
177+
})
178+
)
179+
})
180+
157181
it('uses copilot-facing file schemas for integration tools', async () => {
158182
mockGetHighestPrioritySubscription.mockResolvedValue({ plan: 'pro', status: 'active' })
159183

@@ -174,11 +198,13 @@ describe('buildIntegrationToolSchemas', () => {
174198

175199
const first = await buildIntegrationToolSchemas('user-cache')
176200
first[0].input_schema.mutated = true
201+
if (first[0].outputs) first[0].outputs.mutated = true
177202
const second = await buildIntegrationToolSchemas('user-cache')
178203

179204
expect(mockGetHighestPrioritySubscription).toHaveBeenCalledTimes(1)
180205
expect(mockCreateUserToolSchema).toHaveBeenCalledTimes(3)
181206
expect(second[0].input_schema).not.toHaveProperty('mutated')
207+
expect(second[0].outputs).not.toHaveProperty('mutated')
182208
})
183209
})
184210

apps/sim/lib/copilot/chat/payload.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export interface ToolSchema {
5757
name: string
5858
description: string
5959
input_schema: Record<string, unknown>
60+
outputs?: Record<string, unknown>
6061
defer_loading?: boolean
6162
executeLocally?: boolean
6263
params?: Record<string, unknown>
@@ -104,6 +105,7 @@ function cloneToolSchemas(toolSchemas: ToolSchema[]): ToolSchema[] {
104105
input_schema: { ...tool.input_schema },
105106
}
106107
if (tool.params) cloned.params = { ...tool.params }
108+
if (tool.outputs) cloned.outputs = structuredClone(tool.outputs)
107109
if (tool.oauth) cloned.oauth = { ...tool.oauth }
108110
return cloned
109111
})
@@ -236,6 +238,16 @@ async function buildIntegrationToolSchemasUncached(
236238
appendEmailTagline: shouldAppendEmailTagline,
237239
}),
238240
input_schema: { ...userSchema },
241+
...(toolConfig.outputs && {
242+
outputs: Object.fromEntries(
243+
Object.entries(toolConfig.outputs)
244+
.filter(([, output]) => output != null)
245+
.map(([key, output]) => [
246+
key,
247+
{ type: output.type, description: output.description },
248+
])
249+
),
250+
}),
239251
defer_loading: true,
240252
executeLocally:
241253
catalogEntry?.clientExecutable === true || catalogEntry?.route === 'client',
@@ -357,7 +369,9 @@ export async function buildCopilotRequestPayload(
357369
let mothershipTools: ToolSchema[] = []
358370
const payloadLogger = logger.withMetadata({ messageId: userMessageId })
359371

360-
if (effectiveMode === 'build') {
372+
// "superagent" is a legacy wire value for Direct Action mode; both modes
373+
// execute connected-service operations through the main-agent gateway.
374+
if (effectiveMode === 'build' || effectiveMode === 'superagent') {
361375
integrationTools = await buildIntegrationToolSchemas(
362376
userId,
363377
userMessageId,

apps/sim/lib/copilot/generated/tool-catalog-v1.ts

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface ToolCatalogEntry {
99
id:
1010
| 'agent'
1111
| 'auth'
12+
| 'call_integration_tool'
1213
| 'check_deployment_status'
1314
| 'complete_scheduled_task'
1415
| 'cp'
@@ -85,14 +86,14 @@ export interface ToolCatalogEntry {
8586
| 'scrape_page'
8687
| 'search'
8788
| 'search_documentation'
89+
| 'search_integration_tools'
8890
| 'search_knowledge_base'
8991
| 'search_library_docs'
9092
| 'search_online'
9193
| 'search_patterns'
9294
| 'set_block_enabled'
9395
| 'set_environment_variables'
9496
| 'set_global_workflow_variables'
95-
| 'superagent'
9697
| 'table'
9798
| 'update_deployment_version'
9899
| 'update_scheduled_task_history'
@@ -105,6 +106,7 @@ export interface ToolCatalogEntry {
105106
name:
106107
| 'agent'
107108
| 'auth'
109+
| 'call_integration_tool'
108110
| 'check_deployment_status'
109111
| 'complete_scheduled_task'
110112
| 'cp'
@@ -181,14 +183,14 @@ export interface ToolCatalogEntry {
181183
| 'scrape_page'
182184
| 'search'
183185
| 'search_documentation'
186+
| 'search_integration_tools'
184187
| 'search_knowledge_base'
185188
| 'search_library_docs'
186189
| 'search_online'
187190
| 'search_patterns'
188191
| 'set_block_enabled'
189192
| 'set_environment_variables'
190193
| 'set_global_workflow_variables'
191-
| 'superagent'
192194
| 'table'
193195
| 'update_deployment_version'
194196
| 'update_scheduled_task_history'
@@ -210,7 +212,6 @@ export interface ToolCatalogEntry {
210212
| 'run'
211213
| 'scheduled_task'
212214
| 'search'
213-
| 'superagent'
214215
| 'table'
215216
| 'workflow'
216217
}
@@ -248,6 +249,35 @@ export const Auth: ToolCatalogEntry = {
248249
internal: true,
249250
}
250251

252+
export const CallIntegrationTool: ToolCatalogEntry = {
253+
id: 'call_integration_tool',
254+
name: 'call_integration_tool',
255+
route: 'go',
256+
mode: 'sync',
257+
parameters: {
258+
properties: {
259+
arguments: {
260+
additionalProperties: true,
261+
description: "Inputs matching the selected operation's server-owned inputSchema.",
262+
type: 'object',
263+
},
264+
credentialId: {
265+
description:
266+
'Optional OAuth credential ID convenience field. It is injected into operation arguments when that schema accepts credentialId.',
267+
type: 'string',
268+
},
269+
description: {
270+
description:
271+
'Short present-progressive UI phrase describing this invocation, without the integration name (for example "Searching for invoice emails").',
272+
type: 'string',
273+
},
274+
toolId: { description: 'Exact toolId returned by search_integration_tools.', type: 'string' },
275+
},
276+
required: ['toolId', 'description', 'arguments'],
277+
type: 'object',
278+
},
279+
}
280+
251281
export const CheckDeploymentStatus: ToolCatalogEntry = {
252282
id: 'check_deployment_status',
253283
name: 'check_deployment_status',
@@ -1501,6 +1531,12 @@ export const FunctionExecute: ToolCatalogEntry = {
15011531
},
15021532
},
15031533
},
1534+
timeout: {
1535+
type: 'number',
1536+
description:
1537+
'Maximum execution time in seconds. The sandbox stops execution and returns a timeout error after this duration. Defaults to 10 seconds; the platform execution limit still applies.',
1538+
default: 10,
1539+
},
15041540
title: {
15051541
type: 'string',
15061542
description:
@@ -3633,6 +3669,34 @@ export const SearchDocumentation: ToolCatalogEntry = {
36333669
},
36343670
}
36353671

3672+
export const SearchIntegrationTools: ToolCatalogEntry = {
3673+
id: 'search_integration_tools',
3674+
name: 'search_integration_tools',
3675+
route: 'go',
3676+
mode: 'sync',
3677+
parameters: {
3678+
properties: {
3679+
limit: {
3680+
description: 'Maximum matches to return. Defaults to 5.',
3681+
maximum: 10,
3682+
minimum: 1,
3683+
type: 'integer',
3684+
},
3685+
query: {
3686+
description: 'What the service operation must do, in plain language.',
3687+
type: 'string',
3688+
},
3689+
service: {
3690+
description:
3691+
'Optional canonical service name, such as "gmail", "slack", or "google_sheets".',
3692+
type: 'string',
3693+
},
3694+
},
3695+
required: ['query'],
3696+
type: 'object',
3697+
},
3698+
}
3699+
36363700
export const SearchKnowledgeBase: ToolCatalogEntry = {
36373701
id: 'search_knowledge_base',
36383702
name: 'search_knowledge_base',
@@ -3858,26 +3922,6 @@ export const SetGlobalWorkflowVariables: ToolCatalogEntry = {
38583922
requiredPermission: 'write',
38593923
}
38603924

3861-
export const Superagent: ToolCatalogEntry = {
3862-
id: 'superagent',
3863-
name: 'superagent',
3864-
route: 'subagent',
3865-
mode: 'async',
3866-
parameters: {
3867-
properties: {
3868-
task: {
3869-
description:
3870-
"A single sentence — the agent has full conversation context. Do NOT pre-read credentials or look up configs. Example: 'send the email we discussed' or 'check my calendar for tomorrow'.",
3871-
type: 'string',
3872-
},
3873-
},
3874-
required: ['task'],
3875-
type: 'object',
3876-
},
3877-
subagentId: 'superagent',
3878-
internal: true,
3879-
}
3880-
38813925
export const Table: ToolCatalogEntry = {
38823926
id: 'table',
38833927
name: 'table',
@@ -4307,7 +4351,7 @@ export const Workflow: ToolCatalogEntry = {
43074351
},
43084352
sessionId: {
43094353
description:
4310-
'Reusable session ID returned by an earlier workflow call in this chat. Supply it only on a later user message that continues the same task; the agent resumes from its saved transcript and receives unseen parent conversation messages. Omit it for a new or independent task.',
4354+
'Reusable session ID returned by an earlier workflow call in this chat. Supply it only on a later user message that continues the same task, and at most once per user message — never re-pass a sessionId already used this turn; the agent resumes from its saved transcript and receives unseen parent conversation messages. Omit it for a new or independent task.',
43114355
type: 'string',
43124356
},
43134357
title: {
@@ -4747,6 +4791,7 @@ export const WorkspaceFileOperationValues = [
47474791
export const TOOL_CATALOG: Record<string, ToolCatalogEntry> = {
47484792
[Agent.id]: Agent,
47494793
[Auth.id]: Auth,
4794+
[CallIntegrationTool.id]: CallIntegrationTool,
47504795
[CheckDeploymentStatus.id]: CheckDeploymentStatus,
47514796
[CompleteScheduledTask.id]: CompleteScheduledTask,
47524797
[Cp.id]: Cp,
@@ -4823,14 +4868,14 @@ export const TOOL_CATALOG: Record<string, ToolCatalogEntry> = {
48234868
[ScrapePage.id]: ScrapePage,
48244869
[Search.id]: Search,
48254870
[SearchDocumentation.id]: SearchDocumentation,
4871+
[SearchIntegrationTools.id]: SearchIntegrationTools,
48264872
[SearchKnowledgeBase.id]: SearchKnowledgeBase,
48274873
[SearchLibraryDocs.id]: SearchLibraryDocs,
48284874
[SearchOnline.id]: SearchOnline,
48294875
[SearchPatterns.id]: SearchPatterns,
48304876
[SetBlockEnabled.id]: SetBlockEnabled,
48314877
[SetEnvironmentVariables.id]: SetEnvironmentVariables,
48324878
[SetGlobalWorkflowVariables.id]: SetGlobalWorkflowVariables,
4833-
[Superagent.id]: Superagent,
48344879
[Table.id]: Table,
48354880
[UpdateDeploymentVersion.id]: UpdateDeploymentVersion,
48364881
[UpdateScheduledTaskHistory.id]: UpdateScheduledTaskHistory,

0 commit comments

Comments
 (0)