Skip to content

Commit 8cdcee7

Browse files
committed
fix(mothership): description and incremental vfs both nuked
1 parent 662ecb9 commit 8cdcee7

14 files changed

Lines changed: 117 additions & 93 deletions

apps/sim/lib/copilot/chat/workspace-context.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ describe('buildWorkspaceMd - workflow VFS state paths', () => {
7474
expect(md).toContain('VFS dir: `workflows/Root%20Flow`')
7575
expect(md).toContain('VFS state path: `workflows/Root%20Flow/state.json`')
7676
})
77+
78+
it('never exposes workflow descriptions in markdown or the typed snapshot', () => {
79+
const workflowWithPrivateDescription = {
80+
id: 'wf-1',
81+
name: 'Private Flow',
82+
description: 'PRIVATE WORKFLOW DESCRIPTION',
83+
isDeployed: false,
84+
folderPath: null,
85+
}
86+
const data = baseData({ workflows: [workflowWithPrivateDescription] })
87+
88+
expect(buildWorkspaceMd(data)).not.toContain('PRIVATE WORKFLOW DESCRIPTION')
89+
expect(JSON.stringify(buildVfsSnapshot(data))).not.toContain('PRIVATE WORKFLOW DESCRIPTION')
90+
expect(buildVfsSnapshot(data).workflows?.[0]).not.toHaveProperty('description')
91+
})
7792
})
7893

7994
describe('buildWorkspaceMd - connected integrations / credentials', () => {

apps/sim/lib/copilot/chat/workspace-context.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ export interface WorkspaceMdData {
5555
workflows: Array<{
5656
id: string
5757
name: string
58-
description?: string | null
5958
isDeployed: boolean
6059
lastRunAt?: Date | null
6160
folderPath?: string | null
@@ -158,7 +157,6 @@ export function buildWorkspaceMd(data: WorkspaceMdData): string {
158157
const workflowDir = canonicalWorkflowVfsDir({ name: wf.name, folderPath: wf.folderPath })
159158
parts.push(`${indent} VFS dir: \`${workflowDir}\``)
160159
parts.push(`${indent} VFS state path: \`${workflowDir}/state.json\``)
161-
if (wf.description) parts.push(`${indent} ${wf.description}`)
162160
// `deployed` is a structural flag (kept); `lastRunAt` is intentionally
163161
// omitted — it changes on every run and would bust the cached prompt
164162
// prefix that carries this inventory. Current run data lives in
@@ -366,7 +364,6 @@ async function buildWorkspaceMdData(
366364
.select({
367365
id: workflow.id,
368366
name: workflow.name,
369-
description: workflow.description,
370367
isDeployed: workflow.isDeployed,
371368
lastRunAt: workflow.lastRunAt,
372369
folderId: workflow.folderId,
@@ -589,7 +586,6 @@ export function buildVfsSnapshot(data: WorkspaceMdData): VfsSnapshotV1 {
589586
id: wf.id,
590587
name: wf.name,
591588
path: canonicalWorkflowVfsDir({ name: wf.name, folderPath: wf.folderPath }),
592-
...(wf.description ? { description: wf.description } : {}),
593589
...(wf.isDeployed ? { isDeployed: true } : {}),
594590
...(wf.folderPath ? { folderPath: wf.folderPath } : {}),
595591
}))

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,6 @@ export const CreateWorkflow: ToolCatalogEntry = {
439439
parameters: {
440440
type: 'object',
441441
properties: {
442-
description: { type: 'string', description: 'Optional workflow description.' },
443442
folderId: { type: 'string', description: 'Optional folder ID.' },
444443
name: { type: 'string', description: 'Workflow name.' },
445444
workspaceId: { type: 'string', description: 'Optional workspace ID.' },
@@ -844,7 +843,7 @@ export const DeployCustomBlock: ToolCatalogEntry = {
844843
iconUrl: {
845844
type: 'string',
846845
description:
847-
'Optional icon image for the block: a workspace file VFS path (e.g. "files/icon.png", copied into public icon storage at publish) or an external image URL. Omit to use the organization\'s default icon',
846+
'Optional icon image for the block: a workspace file VFS path (e.g. "files/icon.png", copied into public icon storage at publish) or an https image URL. Omit to use the organization\'s default icon',
848847
},
849848
inputs: {
850849
type: 'array',

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,6 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
221221
parameters: {
222222
type: 'object',
223223
properties: {
224-
description: {
225-
type: 'string',
226-
description: 'Optional workflow description.',
227-
},
228224
folderId: {
229225
type: 'string',
230226
description: 'Optional folder ID.',
@@ -648,7 +644,7 @@ export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {
648644
iconUrl: {
649645
type: 'string',
650646
description:
651-
'Optional icon image for the block: a workspace file VFS path (e.g. "files/icon.png", copied into public icon storage at publish) or an external image URL. Omit to use the organization\'s default icon',
647+
'Optional icon image for the block: a workspace file VFS path (e.g. "files/icon.png", copied into public icon storage at publish) or an https image URL. Omit to use the organization\'s default icon',
652648
},
653649
inputs: {
654650
type: 'array',

apps/sim/lib/copilot/generated/vfs-snapshot-v1.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export interface VfsSnapshotV1Table {
113113
* via the `definition` "VfsSnapshotV1Workflow".
114114
*/
115115
export interface VfsSnapshotV1Workflow {
116-
description?: string
117116
folderPath?: string
118117
id: string
119118
isDeployed?: boolean

apps/sim/lib/copilot/tools/handlers/deployment/deploy.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import { getDeployedWorkflowInputFormat } from '@/lib/mcp/workflow-mcp-sync'
1313
import {
1414
applyDescriptionOverrides,
1515
generateToolInputSchema,
16-
getMeaningfulWorkflowDescription,
1716
sanitizeToolName,
1817
} from '@/lib/mcp/workflow-tool-schema'
1918
import {
@@ -612,9 +611,7 @@ export async function executeDeployMcp(
612611
params.toolName || workflowRecord.name || `workflow_${workflowId}`
613612
)
614613
const toolDescription =
615-
params.toolDescription?.trim() ||
616-
getMeaningfulWorkflowDescription(workflowRecord.description, workflowRecord.name) ||
617-
`Execute ${workflowRecord.name} workflow`
614+
params.toolDescription?.trim() || `Execute ${workflowRecord.name} workflow`
618615
/**
619616
* Parameter names/types come from the workflow's deployed input trigger; this tool only sets
620617
* per-parameter descriptions, sent as sparse overrides. The materialized schema is echoed in the

apps/sim/lib/copilot/tools/handlers/materialize-file.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ vi.mock('@/app/api/v1/admin/types', () => ({ extractWorkflowMetadata: vi.fn() })
5959

6060
import type { ExecutionContext } from '@/lib/copilot/request/types'
6161
import { executeMaterializeFile } from '@/lib/copilot/tools/handlers/materialize-file'
62+
import { fetchWorkspaceFileBuffer } from '@/lib/uploads/contexts/workspace/workspace-file-manager'
63+
import { parseWorkflowJson } from '@/lib/workflows/operations/import-export'
64+
import { saveWorkflowToNormalizedTables } from '@/lib/workflows/persistence/utils'
65+
import { deduplicateWorkflowName } from '@/lib/workflows/utils'
66+
import { extractWorkflowMetadata } from '@/app/api/v1/admin/types'
67+
68+
const fetchWorkspaceFileBufferMock = vi.mocked(fetchWorkspaceFileBuffer)
69+
const parseWorkflowJsonMock = vi.mocked(parseWorkflowJson)
70+
const saveWorkflowToNormalizedTablesMock = vi.mocked(saveWorkflowToNormalizedTables)
71+
const deduplicateWorkflowNameMock = vi.mocked(deduplicateWorkflowName)
72+
const extractWorkflowMetadataMock = vi.mocked(extractWorkflowMetadata)
6273

6374
const context = {
6475
chatId: 'chat-1',
@@ -123,6 +134,45 @@ describe('executeMaterializeFile - unsupported operation', () => {
123134
})
124135
})
125136

137+
describe('executeMaterializeFile - workflow import', () => {
138+
beforeEach(() => {
139+
vi.clearAllMocks()
140+
resetDbChainMock()
141+
mockFindUpload.mockResolvedValue({
142+
...mothershipRow,
143+
originalName: 'workflow.json',
144+
displayName: 'workflow.json',
145+
contentType: 'application/json',
146+
})
147+
fetchWorkspaceFileBufferMock.mockResolvedValue(Buffer.from('{"metadata":{}}'))
148+
parseWorkflowJsonMock.mockReturnValue({
149+
data: { blocks: {}, edges: [], loops: {}, parallels: {}, variables: [] },
150+
errors: [],
151+
})
152+
extractWorkflowMetadataMock.mockReturnValue({
153+
name: 'Imported Workflow',
154+
description: 'PRIVATE WORKFLOW DESCRIPTION',
155+
})
156+
deduplicateWorkflowNameMock.mockResolvedValue('Imported Workflow')
157+
saveWorkflowToNormalizedTablesMock.mockResolvedValue({ success: true })
158+
})
159+
160+
it('does not persist the uploaded workflow description', async () => {
161+
const result = await executeMaterializeFile(
162+
{ fileNames: ['workflow.json'], operation: 'import' },
163+
context
164+
)
165+
166+
expect(result.success).toBe(true)
167+
const insertedWorkflow = dbChainMockFns.values.mock.calls[0]?.[0] as Record<string, unknown>
168+
expect(insertedWorkflow).toMatchObject({ name: 'Imported Workflow' })
169+
expect(insertedWorkflow).not.toHaveProperty('description')
170+
expect(JSON.stringify(dbChainMockFns.values.mock.calls)).not.toContain(
171+
'PRIVATE WORKFLOW DESCRIPTION'
172+
)
173+
})
174+
})
175+
126176
describe('executeMaterializeFile - save storage transition', () => {
127177
beforeEach(() => {
128178
vi.clearAllMocks()

apps/sim/lib/copilot/tools/handlers/materialize-file.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ async function executeImport(
177177
}
178178
}
179179

180-
const { name: rawName, description: workflowDescription } = extractWorkflowMetadata(parsed)
180+
const { name: rawName } = extractWorkflowMetadata(parsed)
181181

182182
const workflowId = generateId()
183183
const now = new Date()
@@ -189,7 +189,6 @@ async function executeImport(
189189
workspaceId,
190190
folderId: null,
191191
name: dedupedName,
192-
description: workflowDescription,
193192
lastSynced: now,
194193
createdAt: now,
195194
updatedAt: now,

apps/sim/lib/copilot/tools/handlers/param-types.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ export interface CreateWorkflowParams {
3333
name?: string
3434
workspaceId?: string
3535
folderId?: string
36-
description?: string
3736
}
3837

3938
export interface CreateFolderParams {
@@ -247,12 +246,6 @@ export interface RenameWorkflowParams {
247246
name: string
248247
}
249248

250-
export interface UpdateWorkflowParams {
251-
workflowId: string
252-
name?: string
253-
description?: string
254-
}
255-
256249
export interface DeleteWorkflowParams {
257250
workflowIds: string[]
258251
}

apps/sim/lib/copilot/tools/handlers/workflow/mutations.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,33 @@ describe('executeCreateWorkflow billing attribution', () => {
293293
reserveExecutionSlotMock.mockResolvedValue({ reserved: true, created: true })
294294
})
295295

296+
it('ignores legacy description input instead of persisting it', async () => {
297+
performCreateWorkflowMock.mockResolvedValue({
298+
success: true,
299+
workflow: {
300+
id: 'created-workflow',
301+
name: 'Created Workflow',
302+
workspaceId: 'workspace-1',
303+
folderId: null,
304+
},
305+
})
306+
const legacyParams = {
307+
name: 'Created Workflow',
308+
workspaceId: 'workspace-1',
309+
description: 'PRIVATE WORKFLOW DESCRIPTION',
310+
} as Parameters<typeof executeCreateWorkflow>[0]
311+
312+
const result = await executeCreateWorkflow(legacyParams, executionContext)
313+
314+
expect(result.success).toBe(true)
315+
expect(performCreateWorkflowMock).toHaveBeenCalledWith({
316+
userId: 'user-1',
317+
workspaceId: 'workspace-1',
318+
name: 'Created Workflow',
319+
folderId: null,
320+
})
321+
})
322+
296323
it('keeps same-workspace creation and subsequent execution on the immutable payer', async () => {
297324
const context: ExecutionContext = { ...executionContext, workflowId: '' }
298325
performCreateWorkflowMock.mockResolvedValue({

0 commit comments

Comments
 (0)