diff --git a/apps/sim/app/api/proxy/video/route.ts b/apps/sim/app/api/proxy/video/route.ts index 01f75fdba9..9aa4091ef6 100644 --- a/apps/sim/app/api/proxy/video/route.ts +++ b/apps/sim/app/api/proxy/video/route.ts @@ -807,18 +807,31 @@ async function generateWithFalAI( // Build request body based on model requirements const requestBody: any = { prompt } - // Format duration based on model requirements - const formattedDuration = formatDuration(model, duration) - if (formattedDuration !== undefined) { - requestBody.duration = formattedDuration - } + // Models that support duration and aspect_ratio parameters + const supportsStandardParams = [ + 'kling-2.5-turbo-pro', + 'kling-2.1-pro', + 'minimax-hailuo-2.3-pro', + 'minimax-hailuo-2.3-standard', + ] + + // Models that only need prompt (minimal params) + const minimalParamModels = ['ltxv-0.9.8', 'wan-2.1', 'veo-3.1', 'sora-2'] + + if (supportsStandardParams.includes(model)) { + // Kling and MiniMax models support duration and aspect_ratio + const formattedDuration = formatDuration(model, duration) + if (formattedDuration !== undefined) { + requestBody.duration = formattedDuration + } - if (aspectRatio) { - requestBody.aspect_ratio = aspectRatio - } + if (aspectRatio) { + requestBody.aspect_ratio = aspectRatio + } - if (resolution) { - requestBody.resolution = resolution + if (resolution) { + requestBody.resolution = resolution + } } // MiniMax models support prompt optimizer diff --git a/apps/sim/app/api/templates/route.ts b/apps/sim/app/api/templates/route.ts index ee4df30e9e..47939ab1ee 100644 --- a/apps/sim/app/api/templates/route.ts +++ b/apps/sim/app/api/templates/route.ts @@ -40,7 +40,7 @@ const CreateTemplateSchema = z.object({ about: z.string().optional(), // Markdown long description }) .optional(), - creatorId: z.string().optional(), // Creator profile ID + creatorId: z.string().min(1, 'Creator profile is required'), tags: z.array(z.string()).max(10, 'Maximum 10 tags allowed').optional().default([]), }) @@ -204,50 +204,47 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: 'Workflow not found' }, { status: 404 }) } - // Validate creator profile if provided - if (data.creatorId) { - // Verify the creator profile exists and user has access - const creatorProfile = await db - .select() - .from(templateCreators) - .where(eq(templateCreators.id, data.creatorId)) - .limit(1) + // Validate creator profile - required for all templates + const creatorProfile = await db + .select() + .from(templateCreators) + .where(eq(templateCreators.id, data.creatorId)) + .limit(1) + + if (creatorProfile.length === 0) { + logger.warn(`[${requestId}] Creator profile not found: ${data.creatorId}`) + return NextResponse.json({ error: 'Creator profile not found' }, { status: 404 }) + } + + const creator = creatorProfile[0] - if (creatorProfile.length === 0) { - logger.warn(`[${requestId}] Creator profile not found: ${data.creatorId}`) - return NextResponse.json({ error: 'Creator profile not found' }, { status: 404 }) + // Verify user has permission to use this creator profile + if (creator.referenceType === 'user') { + if (creator.referenceId !== session.user.id) { + logger.warn(`[${requestId}] User cannot use creator profile: ${data.creatorId}`) + return NextResponse.json( + { error: 'You do not have permission to use this creator profile' }, + { status: 403 } + ) } + } else if (creator.referenceType === 'organization') { + // Verify user is a member of the organization + const membership = await db + .select() + .from(member) + .where( + and(eq(member.userId, session.user.id), eq(member.organizationId, creator.referenceId)) + ) + .limit(1) - const creator = creatorProfile[0] - - // Verify user has permission to use this creator profile - if (creator.referenceType === 'user') { - if (creator.referenceId !== session.user.id) { - logger.warn(`[${requestId}] User cannot use creator profile: ${data.creatorId}`) - return NextResponse.json( - { error: 'You do not have permission to use this creator profile' }, - { status: 403 } - ) - } - } else if (creator.referenceType === 'organization') { - // Verify user is a member of the organization - const membership = await db - .select() - .from(member) - .where( - and(eq(member.userId, session.user.id), eq(member.organizationId, creator.referenceId)) - ) - .limit(1) - - if (membership.length === 0) { - logger.warn( - `[${requestId}] User not a member of organization for creator: ${data.creatorId}` - ) - return NextResponse.json( - { error: 'You must be a member of the organization to use its creator profile' }, - { status: 403 } - ) - } + if (membership.length === 0) { + logger.warn( + `[${requestId}] User not a member of organization for creator: ${data.creatorId}` + ) + return NextResponse.json( + { error: 'You must be a member of the organization to use its creator profile' }, + { status: 403 } + ) } } @@ -307,7 +304,7 @@ export async function POST(request: NextRequest) { workflowId: data.workflowId, name: data.name, details: data.details || null, - creatorId: data.creatorId || null, + creatorId: data.creatorId, views: 0, stars: 0, status: 'pending' as const, // All new templates start as pending diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx index 7d21e3c55b..c4681d677e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/template/template.tsx @@ -89,7 +89,10 @@ export function TemplateDeploy({ const isSubmitting = createMutation.isPending || updateMutation.isPending const isFormValid = - formData.name.trim().length > 0 && formData.name.length <= 100 && formData.tagline.length <= 200 + formData.name.trim().length > 0 && + formData.name.length <= 100 && + formData.tagline.length <= 200 && + formData.creatorId.length > 0 const updateField = (field: K, value: TemplateFormData[K]) => { setFormData((prev) => ({ ...prev, [field]: value })) @@ -201,7 +204,7 @@ export function TemplateDeploy({ tagline: formData.tagline.trim(), about: formData.about.trim(), }, - creatorId: formData.creatorId || undefined, + creatorId: formData.creatorId, tags: formData.tags, } @@ -285,7 +288,7 @@ export function TemplateDeploy({
{creatorOptions.length === 0 && !loadingCreators ? ( - +
+

+ A creator profile is required to publish templates. +

+ +
) : ( ({ diff --git a/apps/sim/blocks/blocks/grafana.ts b/apps/sim/blocks/blocks/grafana.ts index 9b164169f4..5af634fc38 100644 --- a/apps/sim/blocks/blocks/grafana.ts +++ b/apps/sim/blocks/blocks/grafana.ts @@ -298,7 +298,8 @@ export const GrafanaBlock: BlockConfig = { id: 'annotationDashboardUid', title: 'Dashboard UID', type: 'short-input', - placeholder: 'Optional - attach to specific dashboard', + placeholder: 'Enter dashboard UID', + required: true, condition: { field: 'operation', value: ['grafana_create_annotation', 'grafana_list_annotations'], diff --git a/apps/sim/blocks/blocks/video_generator.ts b/apps/sim/blocks/blocks/video_generator.ts index 0e6518be59..86e3576c5e 100644 --- a/apps/sim/blocks/blocks/video_generator.ts +++ b/apps/sim/blocks/blocks/video_generator.ts @@ -169,6 +169,29 @@ export const VideoGeneratorBlock: BlockConfig = { required: false, }, + // Duration selection - Fal.ai (only for Kling and MiniMax models) + { + id: 'duration', + title: 'Duration (seconds)', + type: 'dropdown', + condition: { + field: 'model', + value: [ + 'kling-2.5-turbo-pro', + 'kling-2.1-pro', + 'minimax-hailuo-2.3-pro', + 'minimax-hailuo-2.3-standard', + ], + }, + options: [ + { label: '5', id: '5' }, + { label: '8', id: '8' }, + { label: '10', id: '10' }, + ], + value: () => '5', + required: false, + }, + // Aspect ratio selection - Veo (only 16:9 and 9:16) { id: 'aspectRatio', @@ -213,6 +236,28 @@ export const VideoGeneratorBlock: BlockConfig = { required: false, }, + // Aspect ratio selection - Fal.ai (only for Kling and MiniMax models) + { + id: 'aspectRatio', + title: 'Aspect Ratio', + type: 'dropdown', + condition: { + field: 'model', + value: [ + 'kling-2.5-turbo-pro', + 'kling-2.1-pro', + 'minimax-hailuo-2.3-pro', + 'minimax-hailuo-2.3-standard', + ], + }, + options: [ + { label: '16:9', id: '16:9' }, + { label: '9:16', id: '9:16' }, + ], + value: () => '16:9', + required: false, + }, + // Note: MiniMax aspect ratio is fixed at 16:9 (not configurable) // Note: Runway Gen-4 Turbo outputs at 720p natively (no resolution selector needed) diff --git a/apps/sim/blocks/blocks/zep.ts b/apps/sim/blocks/blocks/zep.ts index 0798986ba1..bd3f43f66a 100644 --- a/apps/sim/blocks/blocks/zep.ts +++ b/apps/sim/blocks/blocks/zep.ts @@ -276,26 +276,26 @@ export const ZepBlock: BlockConfig = { metadata: { type: 'json', description: 'User metadata' }, }, outputs: { + // Thread operations threadId: { type: 'string', description: 'Thread identifier' }, - userId: { type: 'string', description: 'User identifier' }, uuid: { type: 'string', description: 'Internal UUID' }, createdAt: { type: 'string', description: 'Creation timestamp' }, updatedAt: { type: 'string', description: 'Update timestamp' }, threads: { type: 'json', description: 'Array of threads' }, deleted: { type: 'boolean', description: 'Deletion status' }, + // Message operations messages: { type: 'json', description: 'Message data' }, - messageIds: { type: 'json', description: 'Message identifiers' }, - context: { type: 'string', description: 'User context string' }, - facts: { type: 'json', description: 'Extracted facts' }, - entities: { type: 'json', description: 'Extracted entities' }, - summary: { type: 'string', description: 'Conversation summary' }, - batchId: { type: 'string', description: 'Batch operation ID' }, + messageIds: { type: 'json', description: 'Array of added message UUIDs' }, + added: { type: 'boolean', description: 'Whether messages were added successfully' }, + // Context operations + context: { type: 'string', description: 'User context string (summary or basic mode)' }, + // User operations + userId: { type: 'string', description: 'User identifier' }, email: { type: 'string', description: 'User email' }, firstName: { type: 'string', description: 'User first name' }, lastName: { type: 'string', description: 'User last name' }, metadata: { type: 'json', description: 'User metadata' }, - responseCount: { type: 'number', description: 'Number of items in response' }, - totalCount: { type: 'number', description: 'Total number of items available' }, - rowCount: { type: 'number', description: 'Number of rows in response' }, + // Counts + totalCount: { type: 'number', description: 'Total number of items returned' }, }, } diff --git a/apps/sim/tools/grafana/create_annotation.ts b/apps/sim/tools/grafana/create_annotation.ts index e0e846c5d3..6f82235a03 100644 --- a/apps/sim/tools/grafana/create_annotation.ts +++ b/apps/sim/tools/grafana/create_annotation.ts @@ -46,10 +46,9 @@ export const createAnnotationTool: ToolConfig< }, dashboardUid: { type: 'string', - required: false, + required: true, visibility: 'user-or-llm', - description: - 'UID of the dashboard to add the annotation to (optional for global annotations)', + description: 'UID of the dashboard to add the annotation to', }, panelId: { type: 'number', diff --git a/apps/sim/tools/grafana/create_folder.ts b/apps/sim/tools/grafana/create_folder.ts index c4a289c764..08e05e5cc3 100644 --- a/apps/sim/tools/grafana/create_folder.ts +++ b/apps/sim/tools/grafana/create_folder.ts @@ -108,5 +108,45 @@ export const createFolderTool: ToolConfig = { transformResponse: async (response, params) => { const threadId = params.threadId - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, output: { threadId, added: true, + messageIds: [], }, } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, output: { threadId, - context: data.context, + added: true, messageIds: data.message_uuids || [], }, } }, outputs: { - context: { + threadId: { type: 'string', - description: 'Updated context after adding messages', + description: 'The thread ID', + }, + added: { + type: 'boolean', + description: 'Whether messages were added successfully', }, messageIds: { type: 'array', description: 'Array of added message UUIDs', }, - threadId: { - type: 'string', - description: 'The thread ID', - }, }, } diff --git a/apps/sim/tools/zep/add_user.ts b/apps/sim/tools/zep/add_user.ts index 591c0dc43c..97d5281f52 100644 --- a/apps/sim/tools/zep/add_user.ts +++ b/apps/sim/tools/zep/add_user.ts @@ -80,12 +80,12 @@ export const zepAddUserTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, @@ -93,7 +93,7 @@ export const zepAddUserTool: ToolConfig = { } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, diff --git a/apps/sim/tools/zep/create_thread.ts b/apps/sim/tools/zep/create_thread.ts index 6a98d56165..6b33bd82f7 100644 --- a/apps/sim/tools/zep/create_thread.ts +++ b/apps/sim/tools/zep/create_thread.ts @@ -43,12 +43,12 @@ export const zepCreateThreadTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } + const text = await response.text() if (!text || text.trim() === '') { return { success: true, @@ -56,7 +56,7 @@ export const zepCreateThreadTool: ToolConfig = { } } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = JSON.parse(text) return { success: true, diff --git a/apps/sim/tools/zep/get_context.ts b/apps/sim/tools/zep/get_context.ts index 031c3f4c64..609d30a5e2 100644 --- a/apps/sim/tools/zep/get_context.ts +++ b/apps/sim/tools/zep/get_context.ts @@ -53,21 +53,17 @@ export const zepGetContextTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, output: { - context: data.context || data, - facts: data.facts || [], - entities: data.entities || [], - summary: data.summary, + context: data.context, }, } }, @@ -75,19 +71,7 @@ export const zepGetContextTool: ToolConfig = { outputs: { context: { type: 'string', - description: 'The context string (summary or basic)', - }, - facts: { - type: 'array', - description: 'Extracted facts', - }, - entities: { - type: 'array', - description: 'Extracted entities', - }, - summary: { - type: 'string', - description: 'Conversation summary', + description: 'The context string (summary or basic mode)', }, }, } diff --git a/apps/sim/tools/zep/get_messages.ts b/apps/sim/tools/zep/get_messages.ts index 14cf433080..38fca74422 100644 --- a/apps/sim/tools/zep/get_messages.ts +++ b/apps/sim/tools/zep/get_messages.ts @@ -59,13 +59,12 @@ export const zepGetMessagesTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_threads.ts b/apps/sim/tools/zep/get_threads.ts index c6dbc14010..41f9280ddf 100644 --- a/apps/sim/tools/zep/get_threads.ts +++ b/apps/sim/tools/zep/get_threads.ts @@ -61,13 +61,12 @@ export const zepGetThreadsTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_user.ts b/apps/sim/tools/zep/get_user.ts index 2de9346700..b38f1ecff1 100644 --- a/apps/sim/tools/zep/get_user.ts +++ b/apps/sim/tools/zep/get_user.ts @@ -33,13 +33,12 @@ export const zepGetUserTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() return { success: true, diff --git a/apps/sim/tools/zep/get_user_threads.ts b/apps/sim/tools/zep/get_user_threads.ts index a28d7ae7d2..a9acc97dc5 100644 --- a/apps/sim/tools/zep/get_user_threads.ts +++ b/apps/sim/tools/zep/get_user_threads.ts @@ -43,19 +43,19 @@ export const zepGetUserThreadsTool: ToolConfig = { }, transformResponse: async (response) => { - const text = await response.text() - if (!response.ok) { - throw new Error(`Zep API error (${response.status}): ${text || response.statusText}`) + const error = await response.text() + throw new Error(`Zep API error (${response.status}): ${error || response.statusText}`) } - const data = JSON.parse(text.replace(/^\uFEFF/, '').trim()) + const data = await response.json() + const threads = data.threads || data || [] return { success: true, output: { - threads: data.threads || data || [], - userId: data.user_id, + threads, + totalCount: threads.length, }, } }, @@ -65,9 +65,9 @@ export const zepGetUserThreadsTool: ToolConfig = { type: 'array', description: 'Array of thread objects for this user', }, - userId: { - type: 'string', - description: 'The user ID', + totalCount: { + type: 'number', + description: 'Total number of threads returned', }, }, } diff --git a/apps/sim/tools/zep/types.ts b/apps/sim/tools/zep/types.ts index ebbdcce99a..7d8bfe249e 100644 --- a/apps/sim/tools/zep/types.ts +++ b/apps/sim/tools/zep/types.ts @@ -5,7 +5,6 @@ export interface ZepResponse extends ToolResponse { output: { // Thread operations threadId?: string - userId?: string uuid?: string createdAt?: string updatedAt?: string @@ -17,26 +16,18 @@ export interface ZepResponse extends ToolResponse { messages?: any[] messageIds?: string[] added?: boolean - batchId?: string // Context operations context?: string - facts?: any[] - entities?: any[] - summary?: string // User operations + userId?: string email?: string firstName?: string lastName?: string metadata?: any - // Pagination - responseCount?: number + // Counts totalCount?: number - rowCount?: number - - // Search results (if needed in future) - searchResults?: any[] } }