Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,20 @@ import { createLogger } from '@sim/logger'
import { ArrowDown } from 'lucide-react'
import { useRouter } from 'next/navigation'
import { Button, Loader } from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { extractWorkspaceIdFromExecutionKey, getViewerUrl } from '@/lib/uploads/utils/file-utils'
import type { UserFile } from '@/executor/types'

const logger = createLogger('FileCards')

interface FileData {
id?: string
name: string
size: number
type: string
key: string
url: string
uploadedAt: string
expiresAt: string
storageProvider?: 's3' | 'blob' | 'local'
bucketName?: string
}

interface FileCardsProps {
files: FileData[]
files: UserFile[]
isExecutionFile?: boolean
workspaceId?: string
}

interface FileCardProps {
file: FileData
file: UserFile
isExecutionFile?: boolean
workspaceId?: string
}
Expand Down Expand Up @@ -157,7 +146,7 @@ export function FileDownload({
className,
workspaceId,
}: {
file: FileData
file: UserFile
isExecutionFile?: boolean
className?: string
workspaceId?: string
Expand Down Expand Up @@ -220,7 +209,7 @@ export function FileDownload({
return (
<Button
variant='ghost'
className={`h-7 px-2 text-xs ${className}`}
className={cn('h-7 px-2 text-xs', className)}
onClick={handleDownload}
disabled={isDownloading}
>
Expand Down
16 changes: 2 additions & 14 deletions apps/sim/lib/api/contracts/logs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from 'zod'
import { userFileSchema } from '@/lib/api/contracts/primitives'
import { defineRouteContract } from '@/lib/api/contracts/types'

const comparisonOperatorSchema = z.enum(['=', '>', '<', '>=', '<=', '!='])
Expand Down Expand Up @@ -66,19 +67,6 @@ const workflowSummarySchema = z
})
.partial()

const fileSchema = z.object({
id: z.string(),
name: z.string(),
size: z.number(),
type: z.string(),
url: z.string(),
key: z.string(),
uploadedAt: z.string(),
expiresAt: z.string(),
storageProvider: z.enum(['s3', 'blob', 'local']).optional(),
bucketName: z.string().optional(),
})

const tokenBreakdownSchema = z
.object({
total: z.number().optional(),
Expand Down Expand Up @@ -237,7 +225,7 @@ export const workflowLogSummarySchema = z.object({

export const workflowLogDetailSchema = workflowLogSummarySchema.extend({
executionData: executionDataDetailSchema,
files: z.array(fileSchema).nullable(),
files: z.array(userFileSchema).nullable(),
})

export type WorkflowLogSummary = z.output<typeof workflowLogSummarySchema>
Expand Down
20 changes: 20 additions & 0 deletions apps/sim/lib/api/contracts/primitives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ export const workflowIdSchema = z.string().min(1, 'Workflow ID is required')
* Use `.optional()` / `.default(...)` at the call site, not here, so each
* query field controls its own omission/default semantics.
*/
/**
* Canonical boundary schema for `UserFile` (`apps/sim/executor/types.ts`) — the
* shape produced by the executor and persisted in `workflowExecutionLogs.files`,
* forwarded through tool inputs, and rendered in the logs UI. `.passthrough()`
* tolerates legacy/extra fields on stored rows (e.g. `uploadedAt`, `expiresAt`,
* `storageProvider`) without rejecting the whole payload.
*/
export const userFileSchema = z
.object({
id: z.string().optional().default(''),
name: z.string().min(1),
url: z.string().optional().default(''),
size: z.coerce.number().nonnegative(),
type: z.string().optional().default('application/octet-stream'),
key: z.string().min(1),
context: z.string().optional(),
base64: z.string().optional(),
})
.passthrough()

export const booleanQueryFlagSchema = z.preprocess(
(value) => {
if (typeof value === 'boolean') return value
Expand Down
13 changes: 0 additions & 13 deletions apps/sim/lib/api/contracts/tools/media/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,6 @@ import { z } from 'zod'
export const AWS_REGION_PATTERN =
/^(eu-isoe|us-isob|us-iso|us-gov|af|ap|ca|cn|eu|il|me|mx|sa|us)-(central|north|northeast|northwest|south|southeast|southwest|east|west)-\d{1,2}$/

export const mediaUserFileSchema = z
.object({
id: z.string().optional().default(''),
name: z.string().min(1),
url: z.string().optional().default(''),
size: z.coerce.number().nonnegative(),
type: z.string().optional().default('application/octet-stream'),
key: z.string().min(1),
context: z.string().optional(),
base64: z.string().optional(),
})
.passthrough()

export const toolJsonResponseSchema = z
.object({
success: z.boolean().optional(),
Expand Down
5 changes: 3 additions & 2 deletions apps/sim/lib/api/contracts/tools/media/stt.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { z } from 'zod'
import { mediaUserFileSchema, toolJsonResponseSchema } from '@/lib/api/contracts/tools/media/shared'
import { userFileSchema } from '@/lib/api/contracts/primitives'
import { toolJsonResponseSchema } from '@/lib/api/contracts/tools/media/shared'
import { defineRouteContract } from '@/lib/api/contracts/types'

export const sttProviders = ['whisper', 'deepgram', 'elevenlabs', 'assemblyai', 'gemini'] as const
const MISSING_STT_FIELDS_ERROR = 'Missing required fields: provider and apiKey'

export const sttUserFileSchema = mediaUserFileSchema.extend({
export const sttUserFileSchema = userFileSchema.extend({
type: z.string().optional().default(''),
})

Expand Down
5 changes: 3 additions & 2 deletions apps/sim/lib/api/contracts/tools/media/video.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { z } from 'zod'
import { mediaUserFileSchema, toolJsonResponseSchema } from '@/lib/api/contracts/tools/media/shared'
import { userFileSchema } from '@/lib/api/contracts/primitives'
import { toolJsonResponseSchema } from '@/lib/api/contracts/tools/media/shared'
import { defineRouteContract } from '@/lib/api/contracts/types'

export const videoProviders = ['runway', 'veo', 'luma', 'minimax', 'falai'] as const
Expand All @@ -19,7 +20,7 @@ export const videoToolBodySchema = z
duration: z.coerce.number().optional(),
aspectRatio: z.string().optional(),
resolution: z.string().optional(),
visualReference: mediaUserFileSchema.optional(),
visualReference: userFileSchema.optional(),
cameraControl: z.unknown().optional(),
endpoint: z.string().optional(),
promptOptimizer: z.boolean().optional(),
Expand Down
Loading