Skip to content

Commit 59df90a

Browse files
committed
Fix bugs
1 parent a10f32d commit 59df90a

File tree

9 files changed

+251
-51
lines changed

9 files changed

+251
-51
lines changed

apps/sim/app/api/workflows/[id]/chat/status/route.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ export async function GET(_request: Request, { params }: { params: Promise<{ id:
2222
.select({
2323
id: chat.id,
2424
identifier: chat.identifier,
25+
title: chat.title,
26+
description: chat.description,
27+
customizations: chat.customizations,
28+
authType: chat.authType,
29+
allowedEmails: chat.allowedEmails,
30+
outputConfigs: chat.outputConfigs,
31+
password: chat.password,
2532
isActive: chat.isActive,
2633
})
2734
.from(chat)
@@ -34,6 +41,13 @@ export async function GET(_request: Request, { params }: { params: Promise<{ id:
3441
? {
3542
id: deploymentResults[0].id,
3643
identifier: deploymentResults[0].identifier,
44+
title: deploymentResults[0].title,
45+
description: deploymentResults[0].description,
46+
customizations: deploymentResults[0].customizations,
47+
authType: deploymentResults[0].authType,
48+
allowedEmails: deploymentResults[0].allowedEmails,
49+
outputConfigs: deploymentResults[0].outputConfigs,
50+
hasPassword: Boolean(deploymentResults[0].password),
3751
}
3852
: null
3953

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { type FC, memo, useCallback, useMemo, useState } from 'react'
3+
import { type FC, memo, useCallback, useMemo, useRef, useState } from 'react'
44
import { RotateCcw } from 'lucide-react'
55
import { Button } from '@/components/emcn'
66
import {
@@ -93,6 +93,8 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
9393
// UI state
9494
const [isHoveringMessage, setIsHoveringMessage] = useState(false)
9595

96+
const cancelEditRef = useRef<(() => void) | null>(null)
97+
9698
// Checkpoint management hook
9799
const {
98100
showRestoreConfirmation,
@@ -112,7 +114,8 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
112114
messages,
113115
messageCheckpoints,
114116
onRevertModeChange,
115-
onEditModeChange
117+
onEditModeChange,
118+
() => cancelEditRef.current?.()
116119
)
117120

118121
// Message editing hook
@@ -142,6 +145,8 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
142145
pendingEditRef,
143146
})
144147

148+
cancelEditRef.current = handleCancelEdit
149+
145150
// Get clean text content with double newline parsing
146151
const cleanTextContent = useMemo(() => {
147152
if (!message.content) return ''

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/hooks/use-checkpoint-management.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ export function useCheckpointManagement(
2222
messages: CopilotMessage[],
2323
messageCheckpoints: any[],
2424
onRevertModeChange?: (isReverting: boolean) => void,
25-
onEditModeChange?: (isEditing: boolean) => void
25+
onEditModeChange?: (isEditing: boolean) => void,
26+
onCancelEdit?: () => void
2627
) {
2728
const [showRestoreConfirmation, setShowRestoreConfirmation] = useState(false)
2829
const [showCheckpointDiscardModal, setShowCheckpointDiscardModal] = useState(false)
@@ -154,6 +155,8 @@ export function useCheckpointManagement(
154155
}
155156

156157
setShowCheckpointDiscardModal(false)
158+
onEditModeChange?.(false)
159+
onCancelEdit?.()
157160

158161
const { sendMessage } = useCopilotStore.getState()
159162
if (pendingEditRef.current) {
@@ -180,13 +183,22 @@ export function useCheckpointManagement(
180183
} finally {
181184
setIsProcessingDiscard(false)
182185
}
183-
}, [messageCheckpoints, revertToCheckpoint, message, messages])
186+
}, [
187+
messageCheckpoints,
188+
revertToCheckpoint,
189+
message,
190+
messages,
191+
onEditModeChange,
192+
onCancelEdit,
193+
])
184194

185195
/**
186196
* Cancels checkpoint discard and clears pending edit
187197
*/
188198
const handleCancelCheckpointDiscard = useCallback(() => {
189199
setShowCheckpointDiscardModal(false)
200+
onEditModeChange?.(false)
201+
onCancelEdit?.()
190202
pendingEditRef.current = null
191203
}, [])
192204

@@ -218,7 +230,7 @@ export function useCheckpointManagement(
218230
}
219231
pendingEditRef.current = null
220232
}
221-
}, [message, messages])
233+
}, [message, messages, onEditModeChange, onCancelEdit])
222234

223235
/**
224236
* Handles keyboard events for restore confirmation (Escape/Enter)

apps/sim/lib/copilot/tools/client/init-tool-configs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import './workflow/deploy-api'
2828
import './workflow/deploy-chat'
2929
import './workflow/deploy-mcp'
3030
import './workflow/edit-workflow'
31+
import './workflow/redeploy'
3132
import './workflow/run-workflow'
3233
import './workflow/set-global-workflow-variables'
3334

apps/sim/lib/copilot/tools/client/workflow/check-deployment-status.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,23 @@ interface ApiDeploymentDetails {
1515
isDeployed: boolean
1616
deployedAt: string | null
1717
endpoint: string | null
18+
apiKey: string | null
19+
needsRedeployment: boolean
1820
}
1921

2022
interface ChatDeploymentDetails {
2123
isDeployed: boolean
2224
chatId: string | null
2325
identifier: string | null
2426
chatUrl: string | null
27+
title: string | null
28+
description: string | null
29+
authType: string | null
30+
allowedEmails: string[] | null
31+
outputConfigs: Array<{ blockId: string; path: string }> | null
32+
welcomeMessage: string | null
33+
primaryColor: string | null
34+
hasPassword: boolean
2535
}
2636

2737
interface McpDeploymentDetails {
@@ -31,6 +41,8 @@ interface McpDeploymentDetails {
3141
serverName: string
3242
toolName: string
3343
toolDescription: string | null
44+
parameterSchema?: Record<string, unknown> | null
45+
toolId?: string | null
3446
}>
3547
}
3648

@@ -96,6 +108,8 @@ export class CheckDeploymentStatusClientTool extends BaseClientTool {
96108
isDeployed: isApiDeployed,
97109
deployedAt: apiDeploy?.deployedAt || null,
98110
endpoint: isApiDeployed ? `${appUrl}/api/workflows/${workflowId}/execute` : null,
111+
apiKey: apiDeploy?.apiKey || null,
112+
needsRedeployment: apiDeploy?.needsRedeployment === true,
99113
}
100114

101115
// Chat deployment details
@@ -105,6 +119,18 @@ export class CheckDeploymentStatusClientTool extends BaseClientTool {
105119
chatId: chatDeploy?.deployment?.id || null,
106120
identifier: chatDeploy?.deployment?.identifier || null,
107121
chatUrl: isChatDeployed ? `${appUrl}/chat/${chatDeploy?.deployment?.identifier}` : null,
122+
title: chatDeploy?.deployment?.title || null,
123+
description: chatDeploy?.deployment?.description || null,
124+
authType: chatDeploy?.deployment?.authType || null,
125+
allowedEmails: Array.isArray(chatDeploy?.deployment?.allowedEmails)
126+
? chatDeploy?.deployment?.allowedEmails
127+
: null,
128+
outputConfigs: Array.isArray(chatDeploy?.deployment?.outputConfigs)
129+
? chatDeploy?.deployment?.outputConfigs
130+
: null,
131+
welcomeMessage: chatDeploy?.deployment?.customizations?.welcomeMessage || null,
132+
primaryColor: chatDeploy?.deployment?.customizations?.primaryColor || null,
133+
hasPassword: chatDeploy?.deployment?.hasPassword === true,
108134
}
109135

110136
// MCP deployment details - find servers that have this workflow as a tool
@@ -129,6 +155,8 @@ export class CheckDeploymentStatusClientTool extends BaseClientTool {
129155
serverName: server.name,
130156
toolName: tool.toolName,
131157
toolDescription: tool.toolDescription,
158+
parameterSchema: tool.parameterSchema ?? null,
159+
toolId: tool.id ?? null,
132160
})
133161
}
134162
}

apps/sim/lib/copilot/tools/client/workflow/deploy-chat.ts

Lines changed: 54 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -208,54 +208,70 @@ export class DeployChatClientTool extends BaseClientTool {
208208
return
209209
}
210210

211-
// Deploy action - validate required fields
212-
if (!args?.identifier && !workflow?.name) {
213-
throw new Error('Either identifier or workflow name is required')
214-
}
211+
this.setState(ClientToolCallState.executing)
215212

216-
if (!args?.title && !workflow?.name) {
217-
throw new Error('Chat title is required')
213+
const statusRes = await fetch(`/api/workflows/${workflowId}/chat/status`)
214+
const statusJson = statusRes.ok ? await statusRes.json() : null
215+
const existingDeployment = statusJson?.deployment || null
216+
217+
const baseIdentifier =
218+
existingDeployment?.identifier || this.generateIdentifier(workflow?.name || 'chat')
219+
const baseTitle = existingDeployment?.title || workflow?.name || 'Chat'
220+
const baseDescription = existingDeployment?.description || ''
221+
const baseAuthType = existingDeployment?.authType || 'public'
222+
const baseWelcomeMessage =
223+
existingDeployment?.customizations?.welcomeMessage || 'Hi there! How can I help you today?'
224+
const basePrimaryColor =
225+
existingDeployment?.customizations?.primaryColor || 'var(--brand-primary-hover-hex)'
226+
const baseAllowedEmails = Array.isArray(existingDeployment?.allowedEmails)
227+
? existingDeployment.allowedEmails
228+
: []
229+
const baseOutputConfigs = Array.isArray(existingDeployment?.outputConfigs)
230+
? existingDeployment.outputConfigs
231+
: []
232+
233+
const identifier = args?.identifier || baseIdentifier
234+
const title = args?.title || baseTitle
235+
const description = args?.description ?? baseDescription
236+
const authType = args?.authType || baseAuthType
237+
const welcomeMessage = args?.welcomeMessage || baseWelcomeMessage
238+
const outputConfigs = args?.outputConfigs || baseOutputConfigs
239+
const allowedEmails = args?.allowedEmails || baseAllowedEmails
240+
const primaryColor = basePrimaryColor
241+
242+
if (!identifier || !title) {
243+
throw new Error('Chat identifier and title are required')
218244
}
219245

220-
const identifier = args?.identifier || this.generateIdentifier(workflow?.name || 'chat')
221-
const title = args?.title || workflow?.name || 'Chat'
222-
const description = args?.description || ''
223-
const authType = args?.authType || 'public'
224-
const welcomeMessage = args?.welcomeMessage || 'Hi there! How can I help you today?'
225-
226-
// Validate auth-specific requirements
227-
if (authType === 'password' && !args?.password) {
246+
if (authType === 'password' && !args?.password && !existingDeployment?.hasPassword) {
228247
throw new Error('Password is required when using password protection')
229248
}
230249

231-
if (
232-
(authType === 'email' || authType === 'sso') &&
233-
(!args?.allowedEmails || args.allowedEmails.length === 0)
234-
) {
250+
if ((authType === 'email' || authType === 'sso') && allowedEmails.length === 0) {
235251
throw new Error(`At least one email or domain is required when using ${authType} access`)
236252
}
237253

238-
this.setState(ClientToolCallState.executing)
239-
240-
const outputConfigs = args?.outputConfigs || []
241-
242254
const payload = {
243255
workflowId,
244256
identifier: identifier.trim(),
245257
title: title.trim(),
246258
description: description.trim(),
247259
customizations: {
248-
primaryColor: 'var(--brand-primary-hover-hex)',
260+
primaryColor,
249261
welcomeMessage: welcomeMessage.trim(),
250262
},
251263
authType,
252264
password: authType === 'password' ? args?.password : undefined,
253-
allowedEmails: authType === 'email' || authType === 'sso' ? args?.allowedEmails : [],
265+
allowedEmails: authType === 'email' || authType === 'sso' ? allowedEmails : [],
254266
outputConfigs,
255267
}
256268

257-
const res = await fetch('/api/chat', {
258-
method: 'POST',
269+
const isUpdating = Boolean(existingDeployment?.id)
270+
const endpoint = isUpdating ? `/api/chat/manage/${existingDeployment.id}` : '/api/chat'
271+
const method = isUpdating ? 'PATCH' : 'POST'
272+
273+
const res = await fetch(endpoint, {
274+
method,
259275
headers: { 'Content-Type': 'application/json' },
260276
body: JSON.stringify(payload),
261277
})
@@ -265,18 +281,18 @@ export class DeployChatClientTool extends BaseClientTool {
265281
if (!res.ok) {
266282
if (json.error === 'Identifier already in use') {
267283
this.setState(ClientToolCallState.error)
268-
await this.markToolComplete(
269-
400,
270-
`The identifier "${identifier}" is already in use. Please choose a different one.`,
271-
{
272-
success: false,
273-
action: 'deploy',
274-
isDeployed: false,
275-
identifier,
276-
error: `Identifier "${identifier}" is already taken`,
277-
errorCode: 'IDENTIFIER_TAKEN',
278-
}
279-
)
284+
await this.markToolComplete(
285+
400,
286+
`The identifier "${identifier}" is already in use. Please choose a different one.`,
287+
{
288+
success: false,
289+
action: 'deploy',
290+
isDeployed: false,
291+
identifier,
292+
error: `Identifier "${identifier}" is already taken`,
293+
errorCode: 'IDENTIFIER_TAKEN',
294+
}
295+
)
280296
return
281297
}
282298

apps/sim/lib/copilot/tools/client/workflow/deploy-mcp.ts

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export class DeployMcpClientTool extends BaseClientTool {
128128

129129
this.setState(ClientToolCallState.executing)
130130

131-
// Build parameter schema with descriptions if provided
132131
let parameterSchema: Record<string, unknown> | undefined
133132
if (args?.parameterDescriptions && args.parameterDescriptions.length > 0) {
134133
const properties: Record<string, { description: string }> = {}
@@ -155,9 +154,49 @@ export class DeployMcpClientTool extends BaseClientTool {
155154
const data = await res.json()
156155

157156
if (!res.ok) {
158-
// Handle specific error cases
159157
if (data.error?.includes('already added')) {
160-
throw new Error('This workflow is already deployed to this MCP server')
158+
const toolsRes = await fetch(
159+
`/api/mcp/workflow-servers/${args.serverId}/tools?workspaceId=${workspaceId}`
160+
)
161+
const toolsJson = toolsRes.ok ? await toolsRes.json() : null
162+
const tools = toolsJson?.data?.tools || []
163+
const existingTool = tools.find((tool: any) => tool.workflowId === workflowId)
164+
if (!existingTool?.id) {
165+
throw new Error('This workflow is already deployed to this MCP server')
166+
}
167+
const patchRes = await fetch(
168+
`/api/mcp/workflow-servers/${args.serverId}/tools/${existingTool.id}?workspaceId=${workspaceId}`,
169+
{
170+
method: 'PATCH',
171+
headers: { 'Content-Type': 'application/json' },
172+
body: JSON.stringify({
173+
toolName: args.toolName?.trim(),
174+
toolDescription: args.toolDescription?.trim(),
175+
parameterSchema,
176+
}),
177+
}
178+
)
179+
const patchJson = patchRes.ok ? await patchRes.json() : null
180+
if (!patchRes.ok) {
181+
const patchError = patchJson?.error || `Failed to update MCP tool (${patchRes.status})`
182+
throw new Error(patchError)
183+
}
184+
const updatedTool = patchJson?.data?.tool
185+
this.setState(ClientToolCallState.success)
186+
await this.markToolComplete(
187+
200,
188+
`Workflow MCP tool updated to "${updatedTool?.toolName || existingTool.toolName}".`,
189+
{
190+
success: true,
191+
toolId: updatedTool?.id || existingTool.id,
192+
toolName: updatedTool?.toolName || existingTool.toolName,
193+
toolDescription: updatedTool?.toolDescription || existingTool.toolDescription,
194+
serverId: args.serverId,
195+
updated: true,
196+
}
197+
)
198+
logger.info('Updated workflow MCP tool', { toolId: existingTool.id })
199+
return
161200
}
162201
if (data.error?.includes('not deployed')) {
163202
throw new Error('Workflow must be deployed before adding as an MCP tool')

0 commit comments

Comments
 (0)