Skip to content

Commit c2bf65f

Browse files
TheodoreSpeaksTheodore Li
andauthored
fix(logs) Run workflows client side in mothership to transmit logs (#3529)
* Run workflows client side in mothership to transmit logs * Initialize set as constant, prevent duplicate execution * Fix lint --------- Co-authored-by: Theodore Li <theo@sim.ai>
1 parent 8927807 commit c2bf65f

File tree

3 files changed

+39
-4
lines changed

3 files changed

+39
-4
lines changed

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { useCallback, useEffect, useRef, useState } from 'react'
22
import { createLogger } from '@sim/logger'
33
import { useQueryClient } from '@tanstack/react-query'
44
import { usePathname } from 'next/navigation'
5+
import { executeRunToolOnClient } from '@/lib/copilot/client-sse/run-tool-execution'
56
import { MOTHERSHIP_CHAT_API_PATH } from '@/lib/copilot/constants'
7+
import { isWorkflowToolName } from '@/lib/copilot/workflow-tools'
68
import { knowledgeKeys } from '@/hooks/queries/kb/knowledge'
79
import { tableKeys } from '@/hooks/queries/tables'
810
import {
@@ -249,6 +251,7 @@ export function useChat(workspaceId: string, initialChatId?: string): UseChatRet
249251
let buffer = ''
250252
const blocks: ContentBlock[] = []
251253
const toolMap = new Map<string, number>()
254+
const clientExecutionStarted = new Set<string>()
252255
let activeSubagent: string | undefined
253256
let lastTableId: string | null = null
254257
let lastWorkflowId: string | null = null
@@ -336,6 +339,7 @@ export function useChat(workspaceId: string, initialChatId?: string): UseChatRet
336339
const id = parsed.toolCallId
337340
const data = getPayloadData(parsed)
338341
const name = parsed.toolName || data?.name || 'unknown'
342+
const isPartial = data?.partial === true
339343
if (!id) break
340344

341345
if (RESOURCE_TOOL_NAMES.has(name)) {
@@ -373,6 +377,18 @@ export function useChat(workspaceId: string, initialChatId?: string): UseChatRet
373377
}
374378
}
375379
flush()
380+
381+
if (
382+
parsed.type === 'tool_call' &&
383+
ui?.clientExecutable &&
384+
isWorkflowToolName(name) &&
385+
!isPartial &&
386+
!clientExecutionStarted.has(id)
387+
) {
388+
clientExecutionStarted.add(id)
389+
const args = data?.arguments ?? data?.input ?? {}
390+
executeRunToolOnClient(id, name, args as Record<string, unknown>)
391+
}
376392
break
377393
}
378394
case 'tool_result': {

apps/sim/app/workspace/[workspaceId]/home/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,15 @@ export interface SSEPayloadUI {
202202
phaseLabel?: string
203203
icon?: string
204204
internal?: boolean
205+
clientExecutable?: boolean
205206
}
206207

207208
export interface SSEPayloadData {
208209
name?: string
209210
ui?: SSEPayloadUI
210211
id?: string
211212
agent?: string
213+
partial?: boolean
212214
arguments?: Record<string, unknown>
213215
input?: Record<string, unknown>
214216
result?: unknown

apps/sim/lib/copilot/orchestrator/sse/handlers/handlers.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type {
1818
StreamingContext,
1919
ToolCallState,
2020
} from '@/lib/copilot/orchestrator/types'
21+
import { isWorkflowToolName } from '@/lib/copilot/workflow-tools'
2122
import { executeToolAndReport, waitForToolCompletion, waitForToolDecision } from './tool-execution'
2223

2324
const logger = createLogger('CopilotSseHandlers')
@@ -265,9 +266,17 @@ export const sseHandlers: Record<string, SSEHandler> = {
265266
})
266267
}
267268

268-
// Non-interactive mode (Mothership/MCP): skip confirmation & client gates,
269-
// execute server-side directly.
270269
if (options.interactive === false) {
270+
if (clientExecutable && isWorkflowToolName(toolName)) {
271+
toolCall.status = 'executing'
272+
const completion = await waitForToolCompletion(
273+
toolCallId,
274+
options.timeout || STREAM_TIMEOUT_MS,
275+
options.abortSignal
276+
)
277+
handleClientCompletion(toolCall, toolCallId, completion)
278+
return
279+
}
271280
if (options.autoExecuteTools !== false) {
272281
fireToolExecution()
273282
}
@@ -514,9 +523,17 @@ export const subAgentHandlers: Record<string, SSEHandler> = {
514523
})
515524
}
516525

517-
// Non-interactive mode (Mothership/MCP): skip confirmation & client gates,
518-
// execute server-side directly.
519526
if (options.interactive === false) {
527+
if (clientExecutable && isWorkflowToolName(toolName)) {
528+
toolCall.status = 'executing'
529+
const completion = await waitForToolCompletion(
530+
toolCallId,
531+
options.timeout || STREAM_TIMEOUT_MS,
532+
options.abortSignal
533+
)
534+
handleClientCompletion(toolCall, toolCallId, completion)
535+
return
536+
}
520537
if (options.autoExecuteTools !== false) {
521538
fireToolExecution()
522539
}

0 commit comments

Comments
 (0)