Skip to content

Commit ffb045f

Browse files
committed
Improve nested tool status presentation
1 parent 2d49305 commit ffb045f

3 files changed

Lines changed: 65 additions & 17 deletions

File tree

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

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -236,20 +236,13 @@ export function ToolCallItem({
236236
}
237237

238238
return (
239-
/* Same left geometry as the agent-group header (16px slot + gap-2): every
240-
row's text lands on the 24px-per-level grid. The slot renders even when
241-
the tool has no icon — internal tools (grep, read, edit_workflow) were
242-
starting 20px left of integration rows, giving a mixed lane three
243-
different text edges. */
244-
<div className='flex min-w-0 items-center gap-2 pl-6'>
245-
<div className='flex size-[16px] flex-shrink-0 items-center justify-center'>
246-
{BlockIcon && (
247-
<BlockIcon
248-
className='size-[14px] text-[var(--text-icon)]'
249-
style={getBareIconStyle(BlockIcon)}
250-
/>
251-
)}
252-
</div>
239+
<div className='flex min-w-0 items-center gap-[6px] pl-6'>
240+
{BlockIcon && (
241+
<BlockIcon
242+
className='size-[14px] flex-shrink-0 text-[var(--text-icon)]'
243+
style={getBareIconStyle(BlockIcon)}
244+
/>
245+
)}
253246
{isExecuting ? (
254247
<ShimmerText className='min-w-0 truncate text-[13px] leading-[18px] [--shimmer-rest:var(--text-secondary)]'>
255248
{title}

apps/sim/lib/copilot/tools/client/store-utils.test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe('resolveToolDisplay', () => {
6464
resolveToolDisplay(ReadTool.id, ClientToolCallState.error, {
6565
path: 'workflows/Elder v2/The Elder/lint.json',
6666
})?.text
67-
).toBe('Attempted to read lint results for The Elder')
67+
).toBe('Attempted to validate The Elder')
6868
expect(
6969
resolveToolDisplay(ReadTool.id, ClientToolCallState.success, {
7070
path: 'tables/CRM/Leads/views.json',
@@ -233,3 +233,24 @@ describe('resolveToolDisplay', () => {
233233
expect(resolveToolDisplay('load_custom_tool', ClientToolCallState.executing)).toBeUndefined()
234234
})
235235
})
236+
237+
describe('lint reads render as validation', () => {
238+
it.each([
239+
[ClientToolCallState.generating, 'Validating The Elder'],
240+
[ClientToolCallState.success, 'Validated The Elder'],
241+
[ClientToolCallState.error, 'Attempted to validate The Elder'],
242+
[ClientToolCallState.aborted, 'Skipped validating The Elder'],
243+
])('state %s -> %s', (state, expected) => {
244+
expect(
245+
resolveToolDisplay('read', state, { path: 'workflows/Elder v2/The Elder/lint.json' })?.text
246+
).toBe(expected)
247+
})
248+
249+
it('only workflow lint artifacts get the verb; other reads keep Reading', () => {
250+
expect(
251+
resolveToolDisplay('read', ClientToolCallState.success, {
252+
path: 'workflows/Elder v2/The Elder/meta.json',
253+
})?.text
254+
).toBe('Read metadata for The Elder')
255+
})
256+
})

apps/sim/lib/copilot/tools/client/store-utils.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,15 @@ function specialToolDisplay(
4545
}
4646

4747
if (toolName === ReadTool.id) {
48-
const target = describeReadTarget(readStringParam(params, 'path'))
48+
const path = readStringParam(params, 'path')
49+
// lint.json is computed at read time, so reading it IS running the checks —
50+
// "Validating X" describes the outcome where "Reading issues in X" would
51+
// describe the mechanism.
52+
const validated = describeValidationReadTarget(path)
53+
if (validated) {
54+
return { text: formatValidatingLabel(validated, state), icon: FileText }
55+
}
56+
const target = describeReadTarget(path)
4957
return {
5058
text: formatReadingLabel(target, state),
5159
icon: FileText,
@@ -83,6 +91,33 @@ function formatReadingLabel(target: string | undefined, state: ClientToolCallSta
8391
}
8492
}
8593

94+
/** The workflow name when `path` is a lint artifact; undefined otherwise. */
95+
function describeValidationReadTarget(path: string | undefined): string | undefined {
96+
if (!path) return undefined
97+
const segments = path
98+
.split('/')
99+
.map((segment) => segment.trim())
100+
.filter(Boolean)
101+
.map(decodeVfsSegmentSafe)
102+
if (segments.length < 2 || segments[segments.length - 1] !== 'lint.json') return undefined
103+
if (VFS_DIR_TO_RESOURCE[segments[0]] !== 'workflow') return undefined
104+
return stripExtension(getLeafResourceSegment(segments))
105+
}
106+
107+
function formatValidatingLabel(target: string, state: ClientToolCallState): string {
108+
switch (state) {
109+
case ClientToolCallState.success:
110+
return `Validated ${target}`
111+
case ClientToolCallState.error:
112+
return `Attempted to validate ${target}`
113+
case ClientToolCallState.rejected:
114+
case ClientToolCallState.aborted:
115+
return `Skipped validating ${target}`
116+
default:
117+
return `Validating ${target}`
118+
}
119+
}
120+
86121
function describeReadTarget(path: string | undefined): string | undefined {
87122
if (!path) return undefined
88123

@@ -127,7 +162,6 @@ function describeReadTarget(path: string | undefined): string | undefined {
127162
const RESOURCE_ARTIFACT_LABELS: Record<string, string> = {
128163
'state.json': '',
129164
'meta.json': 'metadata for',
130-
'lint.json': 'lint results for',
131165
'deployment.json': 'deployment status for',
132166
'versions.json': 'versions of',
133167
'executions.json': 'runs of',

0 commit comments

Comments
 (0)