Skip to content

Commit b3a639a

Browse files
committed
Logs
1 parent 0249ca1 commit b3a639a

5 files changed

Lines changed: 167 additions & 15 deletions

File tree

apps/sim/lib/copilot/orchestrator/tool-executor/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ const SERVER_TOOLS = new Set<string>([
272272
'get_blocks_metadata',
273273
'get_trigger_blocks',
274274
'edit_workflow',
275-
'get_workflow_console',
275+
'get_workflow_logs',
276276
'search_documentation',
277277
'search_online',
278278
'set_environment_variables',
@@ -284,6 +284,7 @@ const SERVER_TOOLS = new Set<string>([
284284
'run_block',
285285
'run_from_block',
286286
'workspace_file',
287+
'get_execution_summary',
287288
])
288289

289290
const SIM_WORKFLOW_TOOL_HANDLERS: Record<
@@ -469,12 +470,13 @@ async function executeServerToolDirect(
469470
context: ExecutionContext
470471
): Promise<ToolCallResult> {
471472
try {
472-
// Inject workflowId from context if not provided in params
473-
// This is needed for tools like set_environment_variables that require workflowId
474473
const enrichedParams = { ...params }
475474
if (!enrichedParams.workflowId && context.workflowId) {
476475
enrichedParams.workflowId = context.workflowId
477476
}
477+
if (!enrichedParams.workspaceId && context.workspaceId) {
478+
enrichedParams.workspaceId = context.workspaceId
479+
}
478480

479481
const result = await routeExecution(toolName, enrichedParams, {
480482
userId: context.userId,

apps/sim/lib/copilot/tools/client/tool-display-registry.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,7 @@ const META_get_trigger_examples: ToolMetadata = {
732732
interrupt: undefined,
733733
}
734734

735-
const META_get_workflow_console: ToolMetadata = {
735+
const META_get_workflow_logs: ToolMetadata = {
736736
displayNames: {
737737
[ClientToolCallState.generating]: { text: 'Fetching execution logs', icon: Loader2 },
738738
[ClientToolCallState.executing]: { text: 'Fetching execution logs', icon: Loader2 },
@@ -2169,6 +2169,26 @@ const META_table: ToolMetadata = {
21692169
},
21702170
}
21712171

2172+
const META_run: ToolMetadata = {
2173+
displayNames: {
2174+
[ClientToolCallState.generating]: { text: 'Running', icon: Loader2 },
2175+
[ClientToolCallState.pending]: { text: 'Running', icon: Loader2 },
2176+
[ClientToolCallState.executing]: { text: 'Running', icon: Loader2 },
2177+
[ClientToolCallState.success]: { text: 'Ran', icon: Play },
2178+
[ClientToolCallState.error]: { text: 'Failed to run', icon: XCircle },
2179+
[ClientToolCallState.rejected]: { text: 'Skipped run', icon: XCircle },
2180+
[ClientToolCallState.aborted]: { text: 'Aborted run', icon: XCircle },
2181+
},
2182+
uiConfig: {
2183+
subagent: {
2184+
streamingLabel: 'Running',
2185+
completedLabel: 'Ran',
2186+
shouldCollapse: true,
2187+
outputArtifacts: [],
2188+
},
2189+
},
2190+
}
2191+
21722192
const META_get_deployed_workflow_state: ToolMetadata = {
21732193
displayNames: {
21742194
[ClientToolCallState.generating]: { text: 'Checking deployed state', icon: Loader2 },
@@ -2330,7 +2350,7 @@ const TOOL_METADATA_BY_ID: Record<string, ToolMetadata> = {
23302350
get_page_contents: META_get_page_contents,
23312351
get_platform_actions: META_get_platform_actions,
23322352
get_trigger_examples: META_get_trigger_examples,
2333-
get_workflow_console: META_get_workflow_console,
2353+
get_workflow_logs: META_get_workflow_logs,
23342354
get_workflow_data: META_get_workflow_data,
23352355
glob: META_glob,
23362356
grep: META_grep,
@@ -2354,6 +2374,7 @@ const TOOL_METADATA_BY_ID: Record<string, ToolMetadata> = {
23542374
rename_workflow: META_rename_workflow,
23552375
remember_debug: META_remember_debug,
23562376
research: META_research,
2377+
run: META_run,
23572378
run_block: META_run_block,
23582379
run_from_block: META_run_from_block,
23592380
run_workflow: META_run_workflow,

apps/sim/lib/copilot/tools/server/router.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import { userTableServerTool } from '@/lib/copilot/tools/server/table/user-table
1111
import { getCredentialsServerTool } from '@/lib/copilot/tools/server/user/get-credentials'
1212
import { setEnvironmentVariablesServerTool } from '@/lib/copilot/tools/server/user/set-environment-variables'
1313
import { editWorkflowServerTool } from '@/lib/copilot/tools/server/workflow/edit-workflow'
14-
import { getWorkflowConsoleServerTool } from '@/lib/copilot/tools/server/workflow/get-workflow-console'
14+
import { getExecutionSummaryServerTool } from '@/lib/copilot/tools/server/workflow/get-execution-summary'
15+
import { getWorkflowLogsServerTool } from '@/lib/copilot/tools/server/workflow/get-workflow-logs'
1516
import { ExecuteResponseSuccessSchema } from '@/lib/copilot/tools/shared/schemas'
1617

1718
export { ExecuteResponseSuccessSchema }
@@ -24,7 +25,8 @@ const serverToolRegistry: Record<string, BaseServerTool> = {
2425
[getBlocksMetadataServerTool.name]: getBlocksMetadataServerTool,
2526
[getTriggerBlocksServerTool.name]: getTriggerBlocksServerTool,
2627
[editWorkflowServerTool.name]: editWorkflowServerTool,
27-
[getWorkflowConsoleServerTool.name]: getWorkflowConsoleServerTool,
28+
[getExecutionSummaryServerTool.name]: getExecutionSummaryServerTool,
29+
[getWorkflowLogsServerTool.name]: getWorkflowLogsServerTool,
2830
[searchDocumentationServerTool.name]: searchDocumentationServerTool,
2931
[searchOnlineServerTool.name]: searchOnlineServerTool,
3032
[setEnvironmentVariablesServerTool.name]: setEnvironmentVariablesServerTool,
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { db } from '@sim/db'
2+
import { workflow, workflowExecutionLogs } from '@sim/db/schema'
3+
import { createLogger } from '@sim/logger'
4+
import { and, desc, eq, type SQL } from 'drizzle-orm'
5+
import type { BaseServerTool, ServerToolContext } from '@/lib/copilot/tools/server/base-tool'
6+
import { checkWorkspaceAccess } from '@/lib/workspaces/permissions/utils'
7+
8+
const logger = createLogger('GetExecutionSummaryServerTool')
9+
10+
interface GetExecutionSummaryArgs {
11+
workspaceId: string
12+
workflowId?: string
13+
limit?: number
14+
status?: 'success' | 'error' | 'all'
15+
}
16+
17+
interface ExecutionSummary {
18+
executionId: string
19+
workflowId: string
20+
workflowName: string | null
21+
status: string
22+
trigger: string
23+
startedAt: string
24+
durationMs: number | null
25+
cost: number | null
26+
error: string | null
27+
}
28+
29+
function extractErrorMessage(executionData: any): string | null {
30+
if (!executionData) return null
31+
return (
32+
executionData?.errorDetails?.error ||
33+
executionData?.errorDetails?.message ||
34+
executionData?.finalOutput?.error ||
35+
executionData?.error ||
36+
null
37+
)
38+
}
39+
40+
export const getExecutionSummaryServerTool: BaseServerTool<
41+
GetExecutionSummaryArgs,
42+
ExecutionSummary[]
43+
> = {
44+
name: 'get_execution_summary',
45+
async execute(
46+
rawArgs: GetExecutionSummaryArgs,
47+
context?: ServerToolContext
48+
): Promise<ExecutionSummary[]> {
49+
const { workspaceId, workflowId, limit = 10, status = 'all' } = rawArgs || {}
50+
51+
if (!workspaceId || typeof workspaceId !== 'string') {
52+
throw new Error('workspaceId is required')
53+
}
54+
if (!context?.userId) {
55+
throw new Error('Unauthorized access')
56+
}
57+
58+
const access = await checkWorkspaceAccess(workspaceId, context.userId)
59+
if (!access.hasAccess) {
60+
throw new Error('Unauthorized workspace access')
61+
}
62+
63+
const clampedLimit = Math.min(Math.max(1, limit), 20)
64+
65+
logger.info('Fetching execution summary', { workspaceId, workflowId, limit: clampedLimit, status })
66+
67+
const conditions: SQL[] = [eq(workflowExecutionLogs.workspaceId, workspaceId)]
68+
69+
if (workflowId) {
70+
conditions.push(eq(workflowExecutionLogs.workflowId, workflowId))
71+
}
72+
73+
if (status === 'error') {
74+
conditions.push(eq(workflowExecutionLogs.level, 'error'))
75+
} else if (status === 'success') {
76+
conditions.push(eq(workflowExecutionLogs.level, 'info'))
77+
}
78+
79+
const rows = await db
80+
.select({
81+
executionId: workflowExecutionLogs.executionId,
82+
workflowId: workflowExecutionLogs.workflowId,
83+
workflowName: workflow.name,
84+
status: workflowExecutionLogs.status,
85+
level: workflowExecutionLogs.level,
86+
trigger: workflowExecutionLogs.trigger,
87+
startedAt: workflowExecutionLogs.startedAt,
88+
totalDurationMs: workflowExecutionLogs.totalDurationMs,
89+
cost: workflowExecutionLogs.cost,
90+
executionData: workflowExecutionLogs.executionData,
91+
})
92+
.from(workflowExecutionLogs)
93+
.leftJoin(workflow, eq(workflowExecutionLogs.workflowId, workflow.id))
94+
.where(and(...conditions))
95+
.orderBy(desc(workflowExecutionLogs.startedAt))
96+
.limit(clampedLimit)
97+
98+
const summaries: ExecutionSummary[] = rows.map((row) => {
99+
const costData = row.cost as any
100+
const errorMsg =
101+
row.level === 'error' ? extractErrorMessage(row.executionData) : null
102+
103+
return {
104+
executionId: row.executionId,
105+
workflowId: row.workflowId,
106+
workflowName: row.workflowName,
107+
status: row.status,
108+
trigger: row.trigger,
109+
startedAt: row.startedAt.toISOString(),
110+
durationMs: row.totalDurationMs ?? null,
111+
cost: costData?.total ? Number(costData.total) : null,
112+
error: errorMsg
113+
? typeof errorMsg === 'string'
114+
? errorMsg
115+
: JSON.stringify(errorMsg)
116+
: null,
117+
}
118+
})
119+
120+
logger.info('Execution summary prepared', {
121+
count: summaries.length,
122+
workspaceId,
123+
})
124+
125+
return summaries
126+
},
127+
}

apps/sim/lib/copilot/tools/server/workflow/get-workflow-console.ts renamed to apps/sim/lib/copilot/tools/server/workflow/get-workflow-logs.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { and, desc, eq } from 'drizzle-orm'
55
import type { BaseServerTool } from '@/lib/copilot/tools/server/base-tool'
66
import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils'
77

8-
const logger = createLogger('GetWorkflowConsoleServerTool')
8+
const logger = createLogger('GetWorkflowLogsServerTool')
99

10-
interface GetWorkflowConsoleArgs {
10+
interface GetWorkflowLogsArgs {
1111
workflowId: string
1212
executionId?: string
1313
limit?: number
@@ -64,15 +64,15 @@ function extractBlockExecutionsFromTraceSpans(traceSpans: any[]): BlockExecution
6464
return blockExecutions
6565
}
6666

67-
export const getWorkflowConsoleServerTool: BaseServerTool<GetWorkflowConsoleArgs, any> = {
68-
name: 'get_workflow_console',
69-
async execute(rawArgs: GetWorkflowConsoleArgs, context?: { userId: string }): Promise<any> {
67+
export const getWorkflowLogsServerTool: BaseServerTool<GetWorkflowLogsArgs, any> = {
68+
name: 'get_workflow_logs',
69+
async execute(rawArgs: GetWorkflowLogsArgs, context?: { userId: string }): Promise<any> {
7070
const {
7171
workflowId,
7272
executionId,
7373
limit = 2,
7474
includeDetails = false,
75-
} = rawArgs || ({} as GetWorkflowConsoleArgs)
75+
} = rawArgs || ({} as GetWorkflowLogsArgs)
7676

7777
if (!workflowId || typeof workflowId !== 'string') {
7878
throw new Error('workflowId is required')
@@ -90,7 +90,7 @@ export const getWorkflowConsoleServerTool: BaseServerTool<GetWorkflowConsoleArgs
9090
throw new Error(authorization.message || 'Unauthorized workflow access')
9191
}
9292

93-
logger.info('Fetching workflow console logs', {
93+
logger.info('Fetching workflow logs', {
9494
workflowId,
9595
executionId,
9696
limit,
@@ -158,7 +158,7 @@ export const getWorkflowConsoleServerTool: BaseServerTool<GetWorkflowConsoleArgs
158158
})
159159

160160
const resultSize = JSON.stringify(simplifiedExecutions).length
161-
logger.info('Workflow console result prepared', {
161+
logger.info('Workflow logs result prepared', {
162162
executionCount: simplifiedExecutions.length,
163163
resultSizeKB: Math.round(resultSize / 1024),
164164
})

0 commit comments

Comments
 (0)