@@ -20,6 +20,8 @@ import {
2020 extractPathFromOutputId ,
2121 parseOutputContentSafely ,
2222} from '@/lib/response-format'
23+ // import { START_BLOCK_RESERVED_FIELDS } from '@/lib/workflows/types'
24+ // import { StartBlockPath, TriggerUtils } from '@/lib/workflows/triggers'
2325import { cn } from '@/lib/utils'
2426import { useScrollManagement } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
2527import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution'
@@ -28,6 +30,8 @@ import { getChatPosition, useChatStore } from '@/stores/chat/store'
2830import { useExecutionStore } from '@/stores/execution/store'
2931import { useTerminalConsoleStore } from '@/stores/terminal'
3032import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
33+ // import { useSubBlockStore } from '@/stores/workflows/subblock/store'
34+ // import { useWorkflowStore } from '@/stores/workflows/workflow/store'
3135import { ChatMessage , OutputSelect } from './components'
3236import { useChatBoundarySync , useChatDrag , useChatFileUpload , useChatResize } from './hooks'
3337
@@ -124,6 +128,39 @@ const formatOutputContent = (output: any): string => {
124128 return ''
125129}
126130
131+ // interface StartInputFormatField {
132+ // id?: string
133+ // name?: string
134+ // type?: string
135+ // value?: unknown
136+ // collapsed?: boolean
137+ // }
138+
139+ // /**
140+ // * Normalizes an input format value into a list of valid fields.
141+ // *
142+ // * @param value - Raw input format value from subblock state.
143+ // * @returns Array of fields with non-empty names.
144+ // */
145+ // const normalizeStartInputFormat = (value: unknown): StartInputFormatField[] => {
146+ // if (!Array.isArray(value)) {
147+ // return []
148+ // }
149+
150+ // return value.filter((field): field is StartInputFormatField => {
151+ // if (!field || typeof field !== 'object') {
152+ // return false
153+ // }
154+
155+ // const name = (field as StartInputFormatField).name
156+ // return typeof name === 'string' && name.trim() !== ''
157+ // })
158+ // }
159+
160+ const CHAT_START_EXAMPLE_JSON = `"input": string,
161+ "conversationId": string,
162+ "files": array<File>`
163+
127164/**
128165 * Floating chat modal component
129166 *
@@ -140,6 +177,9 @@ export function Chat() {
140177 const params = useParams ( )
141178 const workspaceId = params . workspaceId as string
142179 const { activeWorkflowId } = useWorkflowRegistry ( )
180+ // const blocks = useWorkflowStore((state) => state.blocks)
181+ // const triggerWorkflowUpdate = useWorkflowStore((state) => state.triggerUpdate)
182+ // const setSubBlockValue = useSubBlockStore((state) => state.setValue)
143183
144184 // Chat state (UI and messages from unified store)
145185 const {
@@ -190,6 +230,69 @@ export function Chat() {
190230 handleDrop,
191231 } = useChatFileUpload ( )
192232
233+ /**
234+ * Resolves the unified start block for chat execution, if available.
235+ */
236+ // const startBlockCandidate = useMemo(() => {
237+ // if (!activeWorkflowId) {
238+ // return null
239+ // }
240+
241+ // if (!blocks || Object.keys(blocks).length === 0) {
242+ // return null
243+ // }
244+
245+ // const candidate = TriggerUtils.findStartBlock(blocks, 'chat')
246+ // if (!candidate || candidate.path !== StartBlockPath.UNIFIED) {
247+ // return null
248+ // }
249+
250+ // return candidate
251+ // }, [activeWorkflowId, blocks])
252+
253+ // const startBlockId = startBlockCandidate?.blockId ?? null
254+
255+ // /**
256+ // * Reads the current input format for the unified start block from the subblock store,
257+ // * falling back to the workflow store if no explicit value is stored yet.
258+ // */
259+ // const startBlockInputFormat = useSubBlockStore((state) => {
260+ // if (!activeWorkflowId || !startBlockId) {
261+ // return null
262+ // }
263+
264+ // const workflowValues = state.workflowValues[activeWorkflowId]
265+ // const fromStore = workflowValues?.[startBlockId]?.inputFormat
266+ // if (fromStore !== undefined && fromStore !== null) {
267+ // return fromStore
268+ // }
269+
270+ // const startBlock = blocks[startBlockId]
271+ // return startBlock?.subBlocks?.inputFormat?.value ?? null
272+ // })
273+
274+ // /**
275+ // * Determines which reserved start inputs are missing from the input format.
276+ // */
277+ // const missingStartReservedFields = useMemo(() => {
278+ // if (!startBlockId) {
279+ // return START_BLOCK_RESERVED_FIELDS
280+ // }
281+
282+ // const normalizedFields = normalizeStartInputFormat(startBlockInputFormat)
283+ // const existingNames = new Set(
284+ // normalizedFields
285+ // .map((field) => field.name)
286+ // .filter((name): name is string => typeof name === 'string' && name.trim() !== '')
287+ // .map((name) => name.trim())
288+ // )
289+
290+ // return START_BLOCK_RESERVED_FIELDS.filter((fieldName) => !existingNames.has(fieldName))
291+ // }, [startBlockId, startBlockInputFormat])
292+
293+ // const shouldShowConfigureStartInputsButton =
294+ // Boolean(startBlockId) && missingStartReservedFields.length > 0
295+
193296 // Get actual position (default if not set)
194297 const actualPosition = useMemo (
195298 ( ) => getChatPosition ( chatPosition , chatWidth , chatHeight ) ,
@@ -564,6 +667,60 @@ export function Chat() {
564667 setIsChatOpen ( false )
565668 } , [ setIsChatOpen ] )
566669
670+ // /**
671+ // * Adds any missing reserved inputs (input, conversationId, files) to the unified start block.
672+ // */
673+ // const handleConfigureStartInputs = useCallback(() => {
674+ // if (!activeWorkflowId || !startBlockId) {
675+ // logger.warn('Cannot configure start inputs: missing active workflow ID or start block ID')
676+ // return
677+ // }
678+
679+ // try {
680+ // const existingFields = Array.isArray(startBlockInputFormat)
681+ // ? [...startBlockInputFormat]
682+ // : []
683+
684+ // const normalizedExisting = normalizeStartInputFormat(existingFields)
685+ // const existingNames = new Set(
686+ // normalizedExisting
687+ // .map((field) => field.name)
688+ // .filter((name): name is string => typeof name === 'string' && name.trim() !== '')
689+ // .map((name) => name.trim())
690+ // )
691+
692+ // const updatedFields: StartInputFormatField[] = [...existingFields]
693+
694+ // missingStartReservedFields.forEach((fieldName) => {
695+ // if (existingNames.has(fieldName)) {
696+ // return
697+ // }
698+
699+ // const defaultType = fieldName === 'files' ? 'files' : 'string'
700+
701+ // updatedFields.push({
702+ // id: crypto.randomUUID(),
703+ // name: fieldName,
704+ // type: defaultType,
705+ // value: '',
706+ // collapsed: false,
707+ // })
708+ // })
709+
710+ // setSubBlockValue(startBlockId, 'inputFormat', updatedFields)
711+ // triggerWorkflowUpdate()
712+ // } catch (error) {
713+ // logger.error('Failed to configure start block reserved inputs', error)
714+ // }
715+ // }, [
716+ // activeWorkflowId,
717+ // missingStartReservedFields,
718+ // setSubBlockValue,
719+ // startBlockId,
720+ // startBlockInputFormat,
721+ // triggerWorkflowUpdate,
722+ // ])
723+
567724 // Don't render if not open
568725 if ( ! isChatOpen ) return null
569726
@@ -583,17 +740,32 @@ export function Chat() {
583740 >
584741 { /* Header with drag handle */ }
585742 < div
586- className = 'flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between bg-[var(--surface-1)] p-0 active:cursor-grabbing'
743+ className = 'flex h-[32px] flex-shrink-0 cursor-grab items-center justify-between gap-[10px] bg-[var(--surface-1)] p-0 active:cursor-grabbing'
587744 onMouseDown = { handleMouseDown }
588745 >
589- < div className = 'flex items-center' >
590- < span className = 'flex-shrink-0 font-medium text-[14px] text-[var(--text-primary)]' >
591- Chat
592- </ span >
593- </ div >
746+ < span className = 'flex-shrink-0 pr-[2px] font-medium text-[14px] text-[var(--text-primary)]' >
747+ Chat
748+ </ span >
749+
750+ { /* Start inputs button and output selector - with max-width to prevent overflow */ }
751+ < div
752+ className = 'ml-auto flex min-w-0 flex-shrink items-center gap-[6px]'
753+ onMouseDown = { ( e ) => e . stopPropagation ( ) }
754+ >
755+ { /* {shouldShowConfigureStartInputsButton && (
756+ <Badge
757+ variant='outline'
758+ className='cursor-pointer rounded-[6px] flex-none whitespace-nowrap'
759+ title='Add chat inputs to Start block'
760+ onMouseDown={(e) => {
761+ e.stopPropagation()
762+ handleConfigureStartInputs()
763+ }}
764+ >
765+ <span className='whitespace-nowrap text-[12px]'>Add inputs</span>
766+ </Badge>
767+ )} */ }
594768
595- { /* Output selector - centered with mx-auto */ }
596- < div className = 'mr-[6px] ml-auto' onMouseDown = { ( e ) => e . stopPropagation ( ) } >
597769 < OutputSelect
598770 workflowId = { activeWorkflowId }
599771 selectedOutputs = { selectedOutputs }
@@ -605,7 +777,7 @@ export function Chat() {
605777 />
606778 </ div >
607779
608- < div className = 'flex items-center gap-[8px]' >
780+ < div className = 'flex flex-shrink-0 items-center gap-[8px]' >
609781 { /* More menu with actions */ }
610782 < Popover variant = 'default' >
611783 < PopoverTrigger asChild >
@@ -628,22 +800,22 @@ export function Chat() {
628800 < PopoverItem
629801 onClick = { ( e ) => {
630802 e . stopPropagation ( )
631- if ( activeWorkflowId ) clearChat ( activeWorkflowId )
803+ if ( activeWorkflowId ) exportChatCSV ( activeWorkflowId )
632804 } }
633- disabled = { messages . length === 0 }
805+ disabled = { workflowMessages . length === 0 }
634806 >
635- < Trash className = 'h-[14px ] w-[14px ]' />
636- < span > Clear </ span >
807+ < ArrowDownToLine className = 'h-[13px ] w-[13px ]' />
808+ < span > Download </ span >
637809 </ PopoverItem >
638810 < PopoverItem
639811 onClick = { ( e ) => {
640812 e . stopPropagation ( )
641- if ( activeWorkflowId ) exportChatCSV ( activeWorkflowId )
813+ if ( activeWorkflowId ) clearChat ( activeWorkflowId )
642814 } }
643- disabled = { messages . length === 0 }
815+ disabled = { workflowMessages . length === 0 }
644816 >
645- < ArrowDownToLine className = 'h-[14px ] w-[14px ]' />
646- < span > Download </ span >
817+ < Trash className = 'h-[13px ] w-[13px ]' />
818+ < span > Clear </ span >
647819 </ PopoverItem >
648820 </ PopoverScrollArea >
649821 </ PopoverContent >
@@ -662,7 +834,7 @@ export function Chat() {
662834 < div className = 'flex-1 overflow-hidden' >
663835 { workflowMessages . length === 0 ? (
664836 < div className = 'flex h-full items-center justify-center text-[#8D8D8D] text-[13px]' >
665- No messages yet
837+ Workflow input: { '<start.input>' }
666838 </ div >
667839 ) : (
668840 < div ref = { scrollAreaRef } className = 'h-full overflow-y-auto overflow-x-hidden' >
0 commit comments