mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hw1yzWHyqqZmQrviUEhr5b
104 lines
3.2 KiB
Svelte
104 lines
3.2 KiB
Svelte
<script lang="ts">
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { createFlowChatManager } from './FlowChatManager.svelte'
|
|
import FlowConversationsSidebar from './FlowConversationsSidebar.svelte'
|
|
import FlowChatInterface from './FlowChatInterface.svelte'
|
|
import { getContext, untrack } from 'svelte'
|
|
import type { FlowEditorContext } from '../types'
|
|
import type { FlowModule } from '$lib/gen'
|
|
|
|
interface Props {
|
|
onRunFlow: (
|
|
userMessage: string,
|
|
conversationId: string,
|
|
additionalInputs?: Record<string, any>
|
|
) => Promise<string | undefined>
|
|
useStreaming?: boolean
|
|
deploymentInProgress?: boolean
|
|
path: string
|
|
hideSidebar?: boolean
|
|
inputSchema?: Record<string, any>
|
|
/** The flow's modules, used to find which inputs an AI agent step reads directly. */
|
|
flowModules?: FlowModule[]
|
|
/** Wider centered column, for the full-page chat. */
|
|
wideLayout?: boolean
|
|
/** Whether the editor's own test chats are listed. On where testing happens. */
|
|
showTestChats?: boolean
|
|
}
|
|
|
|
let {
|
|
onRunFlow,
|
|
deploymentInProgress = false,
|
|
useStreaming = false,
|
|
path,
|
|
hideSidebar = false,
|
|
inputSchema = undefined,
|
|
flowModules = undefined,
|
|
wideLayout = false,
|
|
showTestChats = false
|
|
}: Props = $props()
|
|
|
|
const flowEditorContext = getContext<FlowEditorContext>('FlowEditorContext')
|
|
|
|
const manager = createFlowChatManager()
|
|
manager.operatingWorkspace = () => flowEditorContext?.opWorkspace?.()
|
|
manager.showTestChats = showTestChats
|
|
|
|
// Initialize manager when component mounts
|
|
$effect(() => {
|
|
if ($workspaceStore) {
|
|
manager.initialize(onRunFlow, path, useStreaming)
|
|
void manager.selectLatestConversation()
|
|
}
|
|
|
|
return () => {
|
|
manager.cleanup()
|
|
}
|
|
})
|
|
|
|
// Initialize InfiniteList when component mounts or flowPath changes
|
|
$effect(() => {
|
|
if ($workspaceStore && path && manager.conversationListComponent) {
|
|
untrack(() => {
|
|
manager.setupInfiniteList()
|
|
})
|
|
}
|
|
})
|
|
|
|
// Everything the chat asks for beyond the message itself. `user_message` is the
|
|
// composer: the server requires that exact argument on a chat-enabled flow and
|
|
// stores it as the conversation's message (execution.rs:644), so the name is a
|
|
// contract rather than the author's choice.
|
|
const additionalInputsSchema = $derived.by(() => {
|
|
const props = inputSchema?.properties ?? {}
|
|
const messageInput = 'user_message'
|
|
const filtered = Object.fromEntries(Object.entries(props).filter(([k]) => k !== messageInput))
|
|
if (Object.keys(filtered).length === 0) return undefined
|
|
const required = inputSchema?.required
|
|
const requiredArray: string[] = Array.isArray(required) ? required : []
|
|
return {
|
|
...inputSchema,
|
|
properties: filtered,
|
|
required: requiredArray.filter((k: string) => k !== messageInput)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<!-- border-t: the line the chat starts at, dividing it from whatever header sits above.
|
|
pb-3: the transcript and composer stop short of the panel edge, the way the session
|
|
chat sits in its own panel. The column's max width and side padding come from
|
|
AIChatDisplay itself. -->
|
|
<div class="flex overflow-hidden flex-1 pb-3 border-t">
|
|
{#if !hideSidebar}
|
|
<FlowConversationsSidebar {manager} />
|
|
{/if}
|
|
<FlowChatInterface
|
|
{manager}
|
|
{deploymentInProgress}
|
|
{additionalInputsSchema}
|
|
{flowModules}
|
|
{path}
|
|
{wideLayout}
|
|
/>
|
|
</div>
|