@burdenoff/microfe-botmanor 2026.1007.1 → 2026.1009.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/botlit/BotlitRoutes.js +58 -146
  2. package/dist/botlit/BotlitRoutes.js.map +1 -1
  3. package/dist/botlit/BotmanorRoot.js.map +1 -1
  4. package/dist/botlit/BotmanorRootInner.js +39 -67
  5. package/dist/botlit/BotmanorRootInner.js.map +1 -1
  6. package/dist/botlit/components/AssistantRuntimeSetupPanel.js +1 -1
  7. package/dist/botlit/components/AssistantRuntimeSetupPanel.js.map +1 -1
  8. package/dist/botlit/components/ModelRegistrationPanel.js +174 -0
  9. package/dist/botlit/components/ModelRegistrationPanel.js.map +1 -0
  10. package/dist/botlit/hooks/internal/workspaceGateway.js +1 -1
  11. package/dist/botlit/hooks/useAssistantRuntimeSetup.js +2 -2
  12. package/dist/botlit/hooks/useAssistantRuntimeSetup.js.map +1 -1
  13. package/dist/botlit/hooks/useBotWorkflow.js +56 -0
  14. package/dist/botlit/hooks/useBotWorkflow.js.map +1 -0
  15. package/dist/botlit/hooks/useLLMProviders.js +94 -50
  16. package/dist/botlit/hooks/useLLMProviders.js.map +1 -1
  17. package/dist/botlit/pages/AgentBuilderPage.js +206 -183
  18. package/dist/botlit/pages/AgentBuilderPage.js.map +1 -1
  19. package/dist/botlit/pages/BotWorkflowTab.js +33 -33
  20. package/dist/botlit/pages/BotWorkflowTab.js.map +1 -1
  21. package/dist/botlit/pages/KnowledgeBaseDetailPage.js +162 -145
  22. package/dist/botlit/pages/KnowledgeBaseDetailPage.js.map +1 -1
  23. package/dist/botlit/pages/SettingsPage.js +129 -66
  24. package/dist/botlit/pages/SettingsPage.js.map +1 -1
  25. package/dist/botlit/providers/BotlitProvider.js +30 -26
  26. package/dist/botlit/providers/BotlitProvider.js.map +1 -1
  27. package/dist/botlit/utils/embedding-models.js +36 -0
  28. package/dist/botlit/utils/embedding-models.js.map +1 -0
  29. package/dist/generated/wspace-operations.js +58 -36
  30. package/dist/generated/wspace-operations.js.map +1 -1
  31. package/package.json +1 -3
@@ -1 +1 @@
1
- {"version":3,"file":"AgentBuilderPage.js","names":[],"sources":["../../../src/botlit/pages/AgentBuilderPage.tsx"],"sourcesContent":["/**\n * Agent Builder Page\n * @module botlit/pages\n *\n * Creates/edits agents with real GraphQL BotlitAgent type:\n * - systemPrompt (string), temperature, maxTokens\n * - capabilities (enum array: MCP_TOOLS, RAG, REASONING, etc.)\n * - llmModelId (reference to LLM model)\n * - type (ASSISTANT, ANALYST, AUTOMATION, SPECIALIST)\n */\n\nimport type { FC } from 'react';\nimport { useState, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { ArrowLeft, Save, Brain, Wrench, Settings, Sparkles } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { useAgent, useCreateAgent, useUpdateAgent } from '../hooks/useAgents';\nimport { useBots } from '../hooks/useBots';\nimport { useLLMProviders, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\n\n/** `BotlitAgentCapability` values the builder offers. */\nconst AGENT_CAPABILITIES = [\n 'MCP_TOOLS',\n 'RAG',\n 'REASONING',\n 'MULTIMODAL',\n 'MEMORY',\n 'CODE_EXECUTION',\n 'A2A',\n 'WEB_BROWSING',\n] as const;\ntype AgentCapability = (typeof AGENT_CAPABILITIES)[number];\n\n/** `BotlitAgentType` values the builder offers. */\nconst AGENT_TYPES = ['ASSISTANT', 'ANALYST', 'AUTOMATION', 'SPECIALIST'] as const;\n\n/** Drops any capability the schema does not declare rather than guessing one. */\nfunction toCapabilities(values: string[]): AgentCapability[] {\n return values.flatMap((value) => {\n const match = AGENT_CAPABILITIES.find((capability) => capability === value);\n return match ? [match] : [];\n });\n}\n\nfunction toAgentType(value: string): (typeof AGENT_TYPES)[number] {\n return toUnion(value, AGENT_TYPES, 'ASSISTANT');\n}\n\ninterface FormDataType {\n name: string;\n slug: string;\n description: string;\n avatar: string;\n tags: string[];\n // Flat fields matching real GraphQL API\n systemPrompt: string;\n temperature: string;\n maxTokens: string;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId: string;\n}\n\nexport const AgentBuilderPage: FC = () => {\n const { agentId } = useParams();\n const { navigateTo, workspaceId } = useBotlit();\n const { data: existingAgent } = useAgent(agentId);\n const { data: bots } = useBots();\n const { data: providers } = useLLMProviders();\n const { data: llmModels } = useLLMModels();\n const [createAgent, createAgentResult] = useCreateAgent();\n const [updateAgent, updateAgentResult] = useUpdateAgent();\n\n const isEditing = !!agentId;\n const [activeStep, setActiveStep] = useState(0);\n\n const [formData, setFormData] = useState<FormDataType>({\n name: '',\n slug: '',\n description: '',\n avatar: '🤖',\n tags: [],\n systemPrompt: 'You are a helpful AI assistant. Be concise, accurate, and friendly.',\n temperature: '0.7',\n maxTokens: '2048',\n type: 'ASSISTANT',\n status: 'DRAFT',\n capabilities: ['MCP_TOOLS', 'REASONING'],\n llmModelId: '',\n });\n\n // Update form when existing agent loads\n useEffect(() => {\n if (existingAgent) {\n const agent = existingAgent as {\n name: string;\n slug: string;\n description?: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId?: string;\n tagIds?: string[];\n };\n setFormData({\n name: agent.name,\n slug: agent.slug,\n description: agent.description || '',\n avatar: '🤖',\n tags: agent.tagIds || [],\n systemPrompt: agent.systemPrompt || '',\n temperature: String(agent.temperature ?? 0.7),\n maxTokens: String(agent.maxTokens ?? 2048),\n type: agent.type || 'ASSISTANT',\n status: agent.status || 'DRAFT',\n capabilities: agent.capabilities || [],\n llmModelId: agent.llmModelId || '',\n });\n }\n }, [existingAgent]);\n\n const steps = [\n { id: 0, label: 'Basic Info', icon: <Sparkles size={18} /> },\n { id: 1, label: 'Prompt', icon: <Brain size={18} /> },\n { id: 2, label: 'LLM Model', icon: <Settings size={18} /> },\n { id: 3, label: 'Tools & Knowledge', icon: <Wrench size={18} /> },\n ];\n\n const avatars = ['🤖', '🧠', '💡', '🎯', '🔧', '📊', '🎧', '💼', '🔍', '⚡', '🌟', '🚀'];\n\n const allCapabilities: { key: AgentCapability; label: string; description: string }[] = [\n { key: 'MCP_TOOLS', label: 'MCP Tools', description: 'Can use MCP tool servers' },\n { key: 'RAG', label: 'RAG', description: 'Retrieval-augmented generation' },\n { key: 'REASONING', label: 'Reasoning', description: 'Advanced reasoning' },\n { key: 'MULTIMODAL', label: 'Multimodal', description: 'Process images & media' },\n { key: 'MEMORY', label: 'Memory', description: 'Conversation memory' },\n { key: 'CODE_EXECUTION', label: 'Code Execution', description: 'Execute code' },\n { key: 'A2A', label: 'A2A', description: 'Agent-to-agent protocol' },\n { key: 'WEB_BROWSING', label: 'Web Browsing', description: 'Browse the web' },\n ];\n\n const toggleCapability = (cap: string) => {\n setFormData((prev) => ({\n ...prev,\n capabilities: prev.capabilities.includes(cap)\n ? prev.capabilities.filter((c) => c !== cap)\n : [...prev.capabilities, cap],\n }));\n };\n\n const handleSave = async () => {\n const slug = formData.slug || formData.name.toLowerCase().replace(/\\s+/g, '-');\n\n try {\n if (isEditing && agentId) {\n await updateAgent({\n agentId,\n input: {\n name: formData.name,\n slug,\n description: formData.description || undefined,\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n type: toAgentType(formData.type),\n },\n });\n toast.success(`Agent \"${formData.name}\" updated successfully`);\n navigateTo(`agents/${agentId}`);\n } else {\n if (!workspaceId) return;\n const agent = await createAgent({\n workspaceId,\n name: formData.name,\n slug,\n type: toAgentType(formData.type),\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n description: formData.description || undefined,\n });\n toast.success(`Agent \"${formData.name}\" created successfully`);\n if (agent?.id) navigateTo(`agents/${agent.id}`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save agent';\n toast.error(message);\n }\n };\n\n const isCreating = createAgentResult.loading;\n const isUpdating = updateAgentResult.loading;\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n <ArrowLeft size={20} />\n </Button>\n <span>{isEditing ? 'Edit Agent' : 'Create New Agent'}</span>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n </div>\n }\n >\n <div className=\"max-w-4xl mx-auto\">\n <PagePurpose className=\"mb-6\" icon={<Sparkles size={18} />}>\n This guided builder walks you through everything an agent needs — its identity and system\n prompt, the model and parameters it runs on, and the tools and knowledge it can reach.\n Work through the steps, then create the agent and test it in chat. You can come back and\n edit any step later.\n </PagePurpose>\n\n {/* Steps */}\n <div className=\"flex items-center justify-between mb-8\">\n {steps.map((step) => (\n <button\n key={step.id}\n onClick={() => setActiveStep(step.id)}\n className={cn(\n 'flex items-center gap-2 px-4 py-2 rounded-lg transition-colors',\n activeStep === step.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:bg-accent'\n )}\n >\n {step.icon}\n <span className=\"font-medium\">{step.label}</span>\n </button>\n ))}\n </div>\n\n {/* Step Content */}\n <div className=\"space-y-6\">\n {activeStep === 0 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n <CardDescription>Set up the agent's identity and purpose</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Avatar Selection */}\n <div>\n <label className=\"text-sm font-medium\">Avatar</label>\n <div className=\"flex gap-2 mt-2 flex-wrap\">\n {avatars.map((avatar) => (\n <button\n key={avatar}\n onClick={() => setFormData({ ...formData, avatar })}\n className={cn(\n 'text-3xl p-2 rounded-lg border-2 transition-colors',\n formData.avatar === avatar\n ? 'border-primary bg-action-primary-bg/10'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n {avatar}\n </button>\n ))}\n </div>\n </div>\n\n <FormField label=\"Agent Name\" required>\n <Input\n placeholder=\"e.g., Customer Support Agent\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Slug\" description=\"URL-friendly identifier\">\n <Input\n placeholder=\"customer-support-agent\"\n value={formData.slug}\n onChange={(e) => setFormData({ ...formData, slug: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"Describe what this agent does...\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n />\n </FormField>\n\n {/* Capabilities */}\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Capabilities</label>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {allCapabilities.map((cap) => (\n <label\n key={cap.key}\n className=\"flex items-start gap-3 p-3 border border-border-subtle rounded-lg cursor-pointer hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-border-default mt-0.5\"\n checked={formData.capabilities.includes(cap.key)}\n onChange={() => toggleCapability(cap.key)}\n />\n <div>\n <p className=\"font-medium text-sm\">{cap.label}</p>\n <p className=\"text-xs text-text-secondary\">{cap.description}</p>\n </div>\n </label>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 1 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Prompt Configuration</CardTitle>\n <CardDescription>Define how the agent communicates and behaves</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField\n label=\"System Prompt\"\n required\n description=\"The core instructions that define the agent's behavior\"\n >\n <Textarea\n placeholder=\"You are a helpful assistant...\"\n value={formData.systemPrompt}\n onChange={(e) => setFormData({ ...formData, systemPrompt: e.target.value })}\n rows={8}\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Temperature\" description=\"Controls randomness (0-2)\">\n <Input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={formData.temperature}\n onChange={(e) => setFormData({ ...formData, temperature: e.target.value })}\n />\n </FormField>\n <FormField label=\"Max Tokens\" description=\"Maximum response length\">\n <Input\n type=\"number\"\n step=\"256\"\n min=\"1\"\n value={formData.maxTokens}\n onChange={(e) => setFormData({ ...formData, maxTokens: e.target.value })}\n />\n </FormField>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 2 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>LLM Configuration</CardTitle>\n <CardDescription>Select the LLM model for this agent</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField label=\"LLM Model\" description=\"Select a model for this agent\">\n <select\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.llmModelId}\n onChange={(e) => setFormData({ ...formData, llmModelId: e.target.value })}\n >\n <option value=\"\">Select a model...</option>\n {llmModels?.map((model: { id: string; name: string; modelId: string }) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.modelId})\n </option>\n ))}\n </select>\n </FormField>\n\n <div className=\"p-4 bg-bg-sunken rounded-lg\">\n <h4 className=\"text-sm font-medium mb-2\">Available Providers</h4>\n <div className=\"grid grid-cols-2 gap-2\">\n {providers?.map((provider: { id: string; name: string; type: string }) => (\n <div key={provider.id} className=\"text-sm\">\n <span className=\"font-medium\">{provider.name}</span>\n <span className=\"text-text-secondary ml-2\">({provider.type})</span>\n </div>\n ))}\n {!providers?.length && (\n <p className=\"text-sm text-text-secondary\">No providers configured</p>\n )}\n </div>\n </div>\n\n {!llmModels?.length && (\n <p className=\"text-sm text-text-secondary\">\n No models available. Configure a provider and add models in Settings.\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n {activeStep === 3 && (\n <div className=\"space-y-6\">\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench size={18} />\n Tools & Knowledge\n </CardTitle>\n <CardDescription>\n Configure tools and knowledge bases for this agent\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"text-center py-12 text-text-secondary\">\n <Wrench className=\"h-10 w-10 mx-auto mb-3 opacity-50\" />\n <p className=\"font-medium\">Tools & Knowledge coming soon</p>\n <p className=\"text-sm mt-2\">\n MCP tool connections and knowledge base bindings will be configurable here in\n a future update.\n </p>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between pt-6\">\n <Button\n variant=\"outline\"\n onClick={() => setActiveStep(Math.max(0, activeStep - 1))}\n disabled={activeStep === 0}\n >\n Previous\n </Button>\n {activeStep < steps.length - 1 ? (\n <Button onClick={() => setActiveStep(activeStep + 1)}>Next</Button>\n ) : (\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n )}\n </div>\n </div>\n </div>\n\n {/* Show bots dropdown if needed */}\n {bots && bots.length > 0 && null}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentBuilderPage.js","names":[],"sources":["../../../src/botlit/pages/AgentBuilderPage.tsx"],"sourcesContent":["/**\n * Agent Builder Page\n * @module botlit/pages\n *\n * Creates/edits agents with real GraphQL BotlitAgent type:\n * - systemPrompt (string), temperature, maxTokens\n * - capabilities (enum array: MCP_TOOLS, RAG, REASONING, etc.)\n * - llmModelId (reference to LLM model)\n * - type (ASSISTANT, ANALYST, AUTOMATION, SPECIALIST)\n */\n\nimport type { FC } from 'react';\nimport { useState, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { toast } from 'sonner';\nimport { useBotlit } from '../providers/BotlitProvider';\nimport { ArrowLeft, Save, Brain, Wrench, Settings, Sparkles } from 'lucide-react';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Input, Textarea, FormField } from '../components/Input';\nimport { useAgent, useCreateAgent, useUpdateAgent } from '../hooks/useAgents';\nimport { useBots } from '../hooks/useBots';\nimport { useLLMProviders, useLLMModels } from '../hooks/useLLMProviders';\nimport { cn } from '../utils/cn';\nimport { toUnion } from '../utils/unions';\nimport { configuredAnswerModels } from '../utils/embedding-models';\n\n/** `BotlitAgentCapability` values the builder offers. */\nconst AGENT_CAPABILITIES = [\n 'MCP_TOOLS',\n 'RAG',\n 'REASONING',\n 'MULTIMODAL',\n 'MEMORY',\n 'CODE_EXECUTION',\n 'A2A',\n 'WEB_BROWSING',\n] as const;\ntype AgentCapability = (typeof AGENT_CAPABILITIES)[number];\n\n/** `BotlitAgentType` values the builder offers. */\nconst AGENT_TYPES = ['ASSISTANT', 'ANALYST', 'AUTOMATION', 'SPECIALIST'] as const;\n\n/** Drops any capability the schema does not declare rather than guessing one. */\nfunction toCapabilities(values: string[]): AgentCapability[] {\n return values.flatMap((value) => {\n const match = AGENT_CAPABILITIES.find((capability) => capability === value);\n return match ? [match] : [];\n });\n}\n\nfunction toAgentType(value: string): (typeof AGENT_TYPES)[number] {\n return toUnion(value, AGENT_TYPES, 'ASSISTANT');\n}\n\ninterface FormDataType {\n name: string;\n slug: string;\n description: string;\n avatar: string;\n tags: string[];\n // Flat fields matching real GraphQL API\n systemPrompt: string;\n temperature: string;\n maxTokens: string;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId: string;\n}\n\nexport const AgentBuilderPage: FC = () => {\n const { agentId } = useParams();\n const { navigateTo, workspaceId } = useBotlit();\n const { data: existingAgent } = useAgent(agentId);\n const { data: bots } = useBots();\n const {\n data: providers,\n loading: providersLoading,\n error: providersError,\n refetch: refetchProviders,\n } = useLLMProviders();\n const {\n data: llmModels,\n loading: modelsLoading,\n error: modelsError,\n refetch: refetchModels,\n } = useLLMModels();\n const catalogLoading = providersLoading || modelsLoading;\n const catalogError = providersError || modelsError;\n const answerModels = configuredAnswerModels(llmModels ?? [], providers ?? []);\n const [createAgent, createAgentResult] = useCreateAgent();\n const [updateAgent, updateAgentResult] = useUpdateAgent();\n\n const isEditing = !!agentId;\n const [activeStep, setActiveStep] = useState(0);\n\n const [formData, setFormData] = useState<FormDataType>({\n name: '',\n slug: '',\n description: '',\n avatar: '🤖',\n tags: [],\n systemPrompt: 'You are a helpful AI assistant. Be concise, accurate, and friendly.',\n temperature: '0.7',\n maxTokens: '2048',\n type: 'ASSISTANT',\n status: 'DRAFT',\n capabilities: ['MCP_TOOLS', 'REASONING'],\n llmModelId: '',\n });\n\n // Update form when existing agent loads\n useEffect(() => {\n if (existingAgent) {\n const agent = existingAgent as {\n name: string;\n slug: string;\n description?: string;\n systemPrompt: string;\n temperature?: number;\n maxTokens?: number;\n type: string;\n status: string;\n capabilities: string[];\n llmModelId?: string;\n tagIds?: string[];\n };\n setFormData({\n name: agent.name,\n slug: agent.slug,\n description: agent.description || '',\n avatar: '🤖',\n tags: agent.tagIds || [],\n systemPrompt: agent.systemPrompt || '',\n temperature: String(agent.temperature ?? 0.7),\n maxTokens: String(agent.maxTokens ?? 2048),\n type: agent.type || 'ASSISTANT',\n status: agent.status || 'DRAFT',\n capabilities: agent.capabilities || [],\n llmModelId: agent.llmModelId || '',\n });\n }\n }, [existingAgent]);\n\n const steps = [\n { id: 0, label: 'Basic Info', icon: <Sparkles size={18} /> },\n { id: 1, label: 'Prompt', icon: <Brain size={18} /> },\n { id: 2, label: 'LLM Model', icon: <Settings size={18} /> },\n { id: 3, label: 'Tools & Knowledge', icon: <Wrench size={18} /> },\n ];\n\n const avatars = ['🤖', '🧠', '💡', '🎯', '🔧', '📊', '🎧', '💼', '🔍', '⚡', '🌟', '🚀'];\n\n const allCapabilities: { key: AgentCapability; label: string; description: string }[] = [\n { key: 'MCP_TOOLS', label: 'MCP Tools', description: 'Can use MCP tool servers' },\n { key: 'RAG', label: 'RAG', description: 'Retrieval-augmented generation' },\n { key: 'REASONING', label: 'Reasoning', description: 'Advanced reasoning' },\n { key: 'MULTIMODAL', label: 'Multimodal', description: 'Process images & media' },\n { key: 'MEMORY', label: 'Memory', description: 'Conversation memory' },\n { key: 'CODE_EXECUTION', label: 'Code Execution', description: 'Execute code' },\n { key: 'A2A', label: 'A2A', description: 'Agent-to-agent protocol' },\n { key: 'WEB_BROWSING', label: 'Web Browsing', description: 'Browse the web' },\n ];\n\n const toggleCapability = (cap: string) => {\n setFormData((prev) => ({\n ...prev,\n capabilities: prev.capabilities.includes(cap)\n ? prev.capabilities.filter((c) => c !== cap)\n : [...prev.capabilities, cap],\n }));\n };\n\n const handleSave = async () => {\n if (\n formData.llmModelId &&\n (catalogLoading ||\n catalogError ||\n !answerModels.some((model) => model.id === formData.llmModelId))\n ) {\n toast.error('Choose an active answer model from the available catalog.');\n return;\n }\n const slug = formData.slug || formData.name.toLowerCase().replace(/\\s+/g, '-');\n\n try {\n if (isEditing && agentId) {\n await updateAgent({\n agentId,\n input: {\n name: formData.name,\n slug,\n description: formData.description || undefined,\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n type: toAgentType(formData.type),\n },\n });\n toast.success(`Agent \"${formData.name}\" updated successfully`);\n navigateTo(`agents/${agentId}`);\n } else {\n if (!workspaceId) return;\n const agent = await createAgent({\n workspaceId,\n name: formData.name,\n slug,\n type: toAgentType(formData.type),\n systemPrompt: formData.systemPrompt,\n temperature: parseFloat(formData.temperature) || 0.7,\n maxTokens: parseInt(formData.maxTokens) || 2048,\n capabilities: toCapabilities(formData.capabilities),\n llmModelId: formData.llmModelId || undefined,\n description: formData.description || undefined,\n });\n toast.success(`Agent \"${formData.name}\" created successfully`);\n if (agent?.id) navigateTo(`agents/${agent.id}`);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to save agent';\n toast.error(message);\n }\n };\n\n const isCreating = createAgentResult.loading;\n const isUpdating = updateAgentResult.loading;\n\n return (\n <PageLayout\n title={\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n <ArrowLeft size={20} />\n </Button>\n <span>{isEditing ? 'Edit Agent' : 'Create New Agent'}</span>\n </div>\n }\n actions={\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n onClick={() => navigateTo(agentId ? `agents/${agentId}` : 'agents')}\n >\n Cancel\n </Button>\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n </div>\n }\n >\n <div className=\"max-w-4xl mx-auto\">\n <PagePurpose className=\"mb-6\" icon={<Sparkles size={18} />}>\n This guided builder walks you through everything an agent needs — its identity and system\n prompt, the model and parameters it runs on, and the tools and knowledge it can reach.\n Work through the steps, then create the agent and test it in chat. You can come back and\n edit any step later.\n </PagePurpose>\n\n {/* Steps */}\n <div className=\"flex items-center justify-between mb-8\">\n {steps.map((step) => (\n <button\n key={step.id}\n onClick={() => setActiveStep(step.id)}\n className={cn(\n 'flex items-center gap-2 px-4 py-2 rounded-lg transition-colors',\n activeStep === step.id\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:bg-accent'\n )}\n >\n {step.icon}\n <span className=\"font-medium\">{step.label}</span>\n </button>\n ))}\n </div>\n\n {/* Step Content */}\n <div className=\"space-y-6\">\n {activeStep === 0 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Basic Information</CardTitle>\n <CardDescription>Set up the agent's identity and purpose</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {/* Avatar Selection */}\n <div>\n <label className=\"text-sm font-medium\">Avatar</label>\n <div className=\"flex gap-2 mt-2 flex-wrap\">\n {avatars.map((avatar) => (\n <button\n key={avatar}\n onClick={() => setFormData({ ...formData, avatar })}\n className={cn(\n 'text-3xl p-2 rounded-lg border-2 transition-colors',\n formData.avatar === avatar\n ? 'border-primary bg-action-primary-bg/10'\n : 'border-border-subtle hover:border-primary/50'\n )}\n >\n {avatar}\n </button>\n ))}\n </div>\n </div>\n\n <FormField label=\"Agent Name\" required>\n <Input\n placeholder=\"e.g., Customer Support Agent\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Slug\" description=\"URL-friendly identifier\">\n <Input\n placeholder=\"customer-support-agent\"\n value={formData.slug}\n onChange={(e) => setFormData({ ...formData, slug: e.target.value })}\n />\n </FormField>\n\n <FormField label=\"Description\">\n <Textarea\n placeholder=\"Describe what this agent does...\"\n value={formData.description}\n onChange={(e) => setFormData({ ...formData, description: e.target.value })}\n rows={3}\n />\n </FormField>\n\n {/* Capabilities */}\n <div>\n <label className=\"text-sm font-medium mb-2 block\">Capabilities</label>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-3\">\n {allCapabilities.map((cap) => (\n <label\n key={cap.key}\n className=\"flex items-start gap-3 p-3 border border-border-subtle rounded-lg cursor-pointer hover:bg-accent\"\n >\n <input\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-border-default mt-0.5\"\n checked={formData.capabilities.includes(cap.key)}\n onChange={() => toggleCapability(cap.key)}\n />\n <div>\n <p className=\"font-medium text-sm\">{cap.label}</p>\n <p className=\"text-xs text-text-secondary\">{cap.description}</p>\n </div>\n </label>\n ))}\n </div>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 1 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>Prompt Configuration</CardTitle>\n <CardDescription>Define how the agent communicates and behaves</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField\n label=\"System Prompt\"\n required\n description=\"The core instructions that define the agent's behavior\"\n >\n <Textarea\n placeholder=\"You are a helpful assistant...\"\n value={formData.systemPrompt}\n onChange={(e) => setFormData({ ...formData, systemPrompt: e.target.value })}\n rows={8}\n className=\"font-mono text-sm\"\n />\n </FormField>\n\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Temperature\" description=\"Controls randomness (0-2)\">\n <Input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n max=\"2\"\n value={formData.temperature}\n onChange={(e) => setFormData({ ...formData, temperature: e.target.value })}\n />\n </FormField>\n <FormField label=\"Max Tokens\" description=\"Maximum response length\">\n <Input\n type=\"number\"\n step=\"256\"\n min=\"1\"\n value={formData.maxTokens}\n onChange={(e) => setFormData({ ...formData, maxTokens: e.target.value })}\n />\n </FormField>\n </div>\n </CardContent>\n </Card>\n )}\n\n {activeStep === 2 && (\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle>LLM Configuration</CardTitle>\n <CardDescription>Select the LLM model for this agent</CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n <FormField label=\"LLM Model\" description=\"Select a model for this agent\">\n {catalogLoading && <p role=\"status\">Loading answer models…</p>}\n {catalogError && (\n <div role=\"alert\">\n <p>Could not load answer models.</p>\n <Button\n variant=\"secondary\"\n onClick={() => {\n void refetchModels();\n void refetchProviders();\n }}\n >\n Retry model catalog\n </Button>\n </div>\n )}\n <select\n aria-label=\"LLM Model\"\n disabled={catalogLoading || Boolean(catalogError)}\n className=\"flex h-10 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm\"\n value={formData.llmModelId}\n onChange={(e) => setFormData({ ...formData, llmModelId: e.target.value })}\n >\n <option value=\"\">Select a model...</option>\n {answerModels.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.modelId})\n </option>\n ))}\n </select>\n </FormField>\n\n <div className=\"p-4 bg-bg-sunken rounded-lg\">\n <h4 className=\"text-sm font-medium mb-2\">Available Providers</h4>\n <div className=\"grid grid-cols-2 gap-2\">\n {providers?.map((provider: { id: string; name: string; type: string }) => (\n <div key={provider.id} className=\"text-sm\">\n <span className=\"font-medium\">{provider.name}</span>\n <span className=\"text-text-secondary ml-2\">({provider.type})</span>\n </div>\n ))}\n {!catalogLoading && !catalogError && !providers?.length && (\n <p className=\"text-sm text-text-secondary\">No providers configured</p>\n )}\n </div>\n </div>\n\n {!catalogLoading && !catalogError && !answerModels.length && (\n <p className=\"text-sm text-text-secondary\">\n No models available. Configure a provider and add models in Settings.\n </p>\n )}\n </CardContent>\n </Card>\n )}\n\n {activeStep === 3 && (\n <div className=\"space-y-6\">\n <Card treatment=\"glass\" glow>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Wrench size={18} />\n Tools & Knowledge\n </CardTitle>\n <CardDescription>\n Configure tools and knowledge bases for this agent\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"text-center py-12 text-text-secondary\">\n <Wrench className=\"h-10 w-10 mx-auto mb-3 opacity-50\" />\n <p className=\"font-medium\">Tools & Knowledge coming soon</p>\n <p className=\"text-sm mt-2\">\n MCP tool connections and knowledge base bindings will be configurable here in\n a future update.\n </p>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n\n {/* Navigation */}\n <div className=\"flex justify-between pt-6\">\n <Button\n variant=\"outline\"\n onClick={() => setActiveStep(Math.max(0, activeStep - 1))}\n disabled={activeStep === 0}\n >\n Previous\n </Button>\n {activeStep < steps.length - 1 ? (\n <Button onClick={() => setActiveStep(activeStep + 1)}>Next</Button>\n ) : (\n <Button\n leftIcon={<Save size={16} />}\n onClick={handleSave}\n isLoading={isCreating || isUpdating}\n disabled={!formData.name || !formData.systemPrompt}\n >\n {isEditing ? 'Save Changes' : 'Create Agent'}\n </Button>\n )}\n </div>\n </div>\n </div>\n\n {/* Show bots dropdown if needed */}\n {bots && bots.length > 0 && null}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -5,9 +5,9 @@ import { Card as r, CardContent as i, CardDescription as a, CardHeader as o, Car
5
5
  import { Button as c } from "../components/Button.js";
6
6
  import { Badge as l, StatusBadge as u } from "../components/Badge.js";
7
7
  import { EmptyState as d } from "../components/EmptyState.js";
8
- import { useCallback as f, useState as p } from "react";
9
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
10
- import { useCreateWorkflow as g, useWorkflowDefinition as _ } from "@burdenoff/fluidgrids-fe-sdk";
8
+ import { useBotWorkflowDefinition as f, useCreateBotWorkflow as p } from "../hooks/useBotWorkflow.js";
9
+ import { useCallback as m, useState as h } from "react";
10
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
11
11
  import { ExternalLink as v, Sparkles as y, Unlink as b, Workflow as x } from "lucide-react";
12
12
  import { toast as S } from "sonner";
13
13
  //#region src/botlit/pages/BotWorkflowTab.tsx
@@ -82,9 +82,9 @@ function j(e, t) {
82
82
  };
83
83
  }
84
84
  var M = ({ botId: w, botName: T, workflowId: E, onWorkflowChanged: D }) => {
85
- let O = e(), { navigateTo: k } = t(), { createWorkflow: M } = g(), [N] = n(), [P, F] = p(!1), { workflow: I, loading: L } = _(void 0, E ?? void 0), R = f((e, t) => {
85
+ let O = e(), { navigateTo: k } = t(), { createWorkflow: M } = p(), [N] = n(), [P, F] = h(!1), { workflow: I, loading: L } = f(void 0, E ?? void 0), R = m((e, t) => {
86
86
  k(`workflows/workflow/${e}/${t || C}`);
87
- }, [k]), z = f(async () => {
87
+ }, [k]), z = m(async () => {
88
88
  F(!0);
89
89
  try {
90
90
  let e = A(), t = `${T} workflow`, n = await M({
@@ -113,7 +113,7 @@ var M = ({ botId: w, botName: T, workflowId: E, onWorkflowChanged: D }) => {
113
113
  R,
114
114
  O,
115
115
  N
116
- ]), B = f(async () => {
116
+ ]), B = m(async () => {
117
117
  if (confirm(O("botlit.botDetail.workflow.unbindConfirm", "Unbind this workflow from the bot? The workflow itself is not deleted."))) {
118
118
  F(!0);
119
119
  try {
@@ -134,69 +134,69 @@ var M = ({ botId: w, botName: T, workflowId: E, onWorkflowChanged: D }) => {
134
134
  O,
135
135
  N
136
136
  ]);
137
- return E ? /* @__PURE__ */ m("div", {
137
+ return E ? /* @__PURE__ */ g("div", {
138
138
  className: "space-y-6",
139
- children: /* @__PURE__ */ h(r, { children: [/* @__PURE__ */ h(o, { children: [/* @__PURE__ */ h(s, {
139
+ children: /* @__PURE__ */ _(r, { children: [/* @__PURE__ */ _(o, { children: [/* @__PURE__ */ _(s, {
140
140
  className: "flex items-center gap-2",
141
- children: [/* @__PURE__ */ m(x, { size: 18 }), O("botlit.botDetail.workflow.bound.title", "Bound workflow")]
142
- }), /* @__PURE__ */ m(a, { children: O("botlit.botDetail.workflow.bound.description", "This workflow defines what the bot does when it is invoked.") })] }), /* @__PURE__ */ h(i, {
141
+ children: [/* @__PURE__ */ g(x, { size: 18 }), O("botlit.botDetail.workflow.bound.title", "Bound workflow")]
142
+ }), /* @__PURE__ */ g(a, { children: O("botlit.botDetail.workflow.bound.description", "This workflow defines what the bot does when it is invoked.") })] }), /* @__PURE__ */ _(i, {
143
143
  className: "space-y-6",
144
- children: [L ? /* @__PURE__ */ m("div", { className: "h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer" }) : I ? /* @__PURE__ */ h("div", {
144
+ children: [L ? /* @__PURE__ */ g("div", { className: "h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer" }) : I ? /* @__PURE__ */ _("div", {
145
145
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
146
146
  children: [
147
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
147
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
148
148
  className: "text-sm text-text-secondary",
149
149
  children: O("botlit.botDetail.workflow.fields.name", "Name")
150
- }), /* @__PURE__ */ m("p", {
150
+ }), /* @__PURE__ */ g("p", {
151
151
  className: "font-medium text-text-primary",
152
152
  children: I.name
153
153
  })] }),
154
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
154
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
155
155
  className: "text-sm text-text-secondary",
156
156
  children: O("botlit.botDetail.workflow.fields.key", "Key")
157
- }), /* @__PURE__ */ m("p", {
157
+ }), /* @__PURE__ */ g("p", {
158
158
  className: "mt-1 break-all font-mono text-sm text-text-primary",
159
159
  children: I.workflowKey
160
160
  })] }),
161
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
161
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
162
162
  className: "text-sm text-text-secondary",
163
163
  children: O("botlit.botDetail.workflow.fields.version", "Version")
164
- }), /* @__PURE__ */ m(l, {
164
+ }), /* @__PURE__ */ g(l, {
165
165
  variant: "outline",
166
166
  className: "mt-1",
167
167
  children: I.version
168
168
  })] }),
169
- /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
169
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("p", {
170
170
  className: "text-sm text-text-secondary",
171
171
  children: O("botlit.botDetail.workflow.fields.status", "Status")
172
- }), /* @__PURE__ */ m("div", {
172
+ }), /* @__PURE__ */ g("div", {
173
173
  className: "mt-1",
174
- children: /* @__PURE__ */ m(u, { status: I.status })
174
+ children: /* @__PURE__ */ g(u, { status: I.status })
175
175
  })] })
176
176
  ]
177
- }) : /* @__PURE__ */ h("div", { children: [
178
- /* @__PURE__ */ m("p", {
177
+ }) : /* @__PURE__ */ _("div", { children: [
178
+ /* @__PURE__ */ g("p", {
179
179
  className: "text-sm text-text-secondary",
180
180
  children: O("botlit.botDetail.workflow.fields.workflowId", "Workflow ID")
181
181
  }),
182
- /* @__PURE__ */ m("p", {
182
+ /* @__PURE__ */ g("p", {
183
183
  className: "mt-1 break-all font-mono text-sm text-text-primary",
184
184
  children: E
185
185
  }),
186
- /* @__PURE__ */ m("p", {
186
+ /* @__PURE__ */ g("p", {
187
187
  className: "mt-2 text-sm text-text-secondary",
188
188
  children: O("botlit.botDetail.workflow.unresolved", "This workflow could not be loaded — it may have been deleted. Unbind it and design a new one.")
189
189
  })
190
- ] }), /* @__PURE__ */ h("div", {
190
+ ] }), /* @__PURE__ */ _("div", {
191
191
  className: "flex flex-wrap gap-2",
192
- children: [I && /* @__PURE__ */ m(c, {
193
- leftIcon: /* @__PURE__ */ m(v, { size: 16 }),
192
+ children: [I && /* @__PURE__ */ g(c, {
193
+ leftIcon: /* @__PURE__ */ g(v, { size: 16 }),
194
194
  disabled: P,
195
195
  onClick: () => R(I.workflowKey, I.version),
196
196
  children: O("botlit.botDetail.workflow.actions.openBuilder", "Open in builder")
197
- }), /* @__PURE__ */ m(c, {
197
+ }), /* @__PURE__ */ g(c, {
198
198
  variant: "outline",
199
- leftIcon: /* @__PURE__ */ m(b, { size: 16 }),
199
+ leftIcon: /* @__PURE__ */ g(b, { size: 16 }),
200
200
  isLoading: P,
201
201
  disabled: P,
202
202
  onClick: () => void B(),
@@ -204,14 +204,14 @@ var M = ({ botId: w, botName: T, workflowId: E, onWorkflowChanged: D }) => {
204
204
  })]
205
205
  })]
206
206
  })] })
207
- }) : /* @__PURE__ */ m(r, { children: /* @__PURE__ */ m(i, {
207
+ }) : /* @__PURE__ */ g(r, { children: /* @__PURE__ */ g(i, {
208
208
  className: "pt-6",
209
- children: /* @__PURE__ */ m(d, {
209
+ children: /* @__PURE__ */ g(d, {
210
210
  illustration: "empty-generic",
211
211
  title: O("botlit.botDetail.workflow.empty.title", "Design this bot as a workflow"),
212
212
  description: O("botlit.botDetail.workflow.empty.description", "A bot's behaviour is designed as a FluidGrids workflow — the visual canvas where you wire triggers, agents, tools and conditions together. Start one and we will create it, bind it to this bot and open the builder for you."),
213
- action: /* @__PURE__ */ m(c, {
214
- leftIcon: /* @__PURE__ */ m(y, { size: 16 }),
213
+ action: /* @__PURE__ */ g(c, {
214
+ leftIcon: /* @__PURE__ */ g(y, { size: 16 }),
215
215
  isLoading: P,
216
216
  disabled: P,
217
217
  onClick: () => void z(),
@@ -1 +1 @@
1
- {"version":3,"file":"BotWorkflowTab.js","names":[],"sources":["../../../src/botlit/pages/BotWorkflowTab.tsx"],"sourcesContent":["/**\n * BotWorkflowTab\n * @module botlit/pages\n *\n * Shown inside BotDetailPage → \"Workflow\" tab.\n *\n * A bot's behaviour is designed as a FluidGrids workflow. `BotApp.workflowId`\n * holds the binding (validated server-side by `assertWorkflowBindingsResolvable`\n * on wspace-botlit-svc), and the FluidGrids builder is already mounted INSIDE\n * BotManor at `workflows/workflow/:id/:version` — so this tab never leaves the\n * product.\n *\n * Flow:\n * 1. Bound → resolve the definition by id (`useWorkflowDefinition`), show\n * name / key / version / status, \"Open in builder\", \"Unbind\".\n * A binding that no longer resolves falls back to the raw id so\n * the user can still clear it.\n * 2. Not bound → zero state whose primary action creates a seeded workflow\n * definition, binds it via `updateBotApp(workflowId)` and drops\n * the user straight into the embedded builder.\n *\n * IMPORTANT — seed graph shape. `BotlitFluidGridsBridge.extractTriggerNodeIds`\n * reads nodes from `definitionJson.data.nodes` (NOT the top level) and treats a\n * node as a trigger when its `type` is `trigger`/`trigger:*`/`*_trigger`, OR its\n * `kind[]` / `data.nodeData.kind[]` contains `trigger`. The seed below uses the\n * workflow service's own BUILTIN manual trigger (`internal:api`, \"Trigger\n * Manually\") — the node the executor resolves as the entry point — and carries\n * `kind: ['trigger', ...]` in both places, so a freshly designed bot is\n * immediately runnable instead of failing with `WORKFLOW_NO_TRIGGER_NODE`.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { ExternalLink, Sparkles, Unlink, Workflow } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useCreateWorkflow, useWorkflowDefinition } from '@burdenoff/fluidgrids-fe-sdk';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useUpdateBot } from '../hooks/useBots';\nimport { useBotlit } from '../providers/BotlitProvider';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Seed graph\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** First version minted for a bot's workflow — matches the builder's own default. */\nconst INITIAL_VERSION = 'v1';\n\n/**\n * BUILTIN \"Trigger Manually\" node (`MANUAL_TRIGGER_MANIFEST` in\n * wspace-workflow-svc). The executor resolves this type as a workflow's entry\n * node, and the builder renders it from the seeded node registry.\n */\nconst MANUAL_TRIGGER_NODE_TYPE = 'internal:api';\nconst MANUAL_TRIGGER_NODE_VERSION = '1.0.0';\nconst MANUAL_TRIGGER_OPERATION = 'onManualTrigger';\nconst MANUAL_TRIGGER_NAME = 'Trigger Manually';\nconst MANUAL_TRIGGER_DESCRIPTION =\n \"Runs the flow when you click 'Test workflow', or when this bot is invoked.\";\n\n/** `kind[]` the BotManor bridge scans for when classifying a node as a trigger. */\nconst MANUAL_TRIGGER_KIND = ['trigger', 'manual', 'entry'];\n\n/** Node shape written into `definitionJson.data.nodes`. */\ntype SeedNode = {\n id: string;\n type: string;\n position: { x: number; y: number };\n /** Top-level kind — the bridge's second trigger-detection path. */\n kind: string[];\n data: {\n operation_name: string;\n operation_type: string;\n version: string;\n nodeData: {\n nodeType: string;\n name: string;\n description: string;\n version: string;\n /** The bridge's third trigger-detection path. */\n kind: string[];\n operations: { name: string; type: string; role: string; description: string }[];\n };\n args: {\n context: { node: { id: string; type: string; kind: string[] } };\n state: Record<string, never>;\n credentials: never[];\n };\n };\n};\n\n/**\n * `definitionJson` document. Mirrors what the builder itself persists\n * (`useSaveWorkflow`) so the graph round-trips through the builder unchanged.\n */\ntype SeedDefinition = {\n key: string;\n name: string;\n description: string;\n workflow_type: string;\n data: {\n id: string;\n workflowKey: string;\n version: string;\n name: string;\n nodes: SeedNode[];\n edges: never[];\n sidebar: { active: string; panels: { nodeProperties: { selectedNode: null } } };\n stickyNotes: never[];\n };\n meta: { creator: string; version: string };\n tags: string[];\n};\n\n/**\n * Generate an opaque id. `crypto.randomUUID` is unavailable on insecure origins\n * and in some test environments, so fall back to a time+random token rather than\n * throwing mid-create.\n */\nfunction generateId(): string {\n const webCrypto = globalThis.crypto as Crypto | undefined;\n if (webCrypto && typeof webCrypto.randomUUID === 'function') {\n return webCrypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Build the starter graph: one manual trigger, nothing else. */\nfunction buildSeedDefinition(workflowKey: string, name: string): SeedDefinition {\n const triggerNode: SeedNode = {\n id: generateId(),\n type: MANUAL_TRIGGER_NODE_TYPE,\n position: { x: 160, y: 160 },\n kind: MANUAL_TRIGGER_KIND,\n data: {\n operation_name: MANUAL_TRIGGER_OPERATION,\n operation_type: 'trigger',\n version: MANUAL_TRIGGER_NODE_VERSION,\n nodeData: {\n nodeType: MANUAL_TRIGGER_NODE_TYPE,\n name: MANUAL_TRIGGER_NAME,\n description: MANUAL_TRIGGER_DESCRIPTION,\n version: MANUAL_TRIGGER_NODE_VERSION,\n kind: MANUAL_TRIGGER_KIND,\n operations: [\n {\n name: MANUAL_TRIGGER_OPERATION,\n type: 'trigger',\n role: 'trigger',\n description: MANUAL_TRIGGER_DESCRIPTION,\n },\n ],\n },\n args: {\n context: {\n node: {\n id: MANUAL_TRIGGER_NODE_TYPE,\n type: MANUAL_TRIGGER_NODE_TYPE,\n kind: MANUAL_TRIGGER_KIND,\n },\n },\n state: {},\n credentials: [],\n },\n },\n };\n\n return {\n key: workflowKey,\n name,\n description: name,\n workflow_type: 'query-conditional',\n data: {\n id: workflowKey,\n workflowKey,\n version: INITIAL_VERSION,\n name,\n nodes: [triggerNode],\n edges: [],\n sidebar: { active: 'store-browse', panels: { nodeProperties: { selectedNode: null } } },\n stickyNotes: [],\n },\n meta: { creator: 'botlit_bot_design', version: INITIAL_VERSION },\n tags: [],\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface BotWorkflowTabProps {\n botId: string;\n botName: string;\n /** `BotApp.workflowId` — the bound workflow definition id, if any. */\n workflowId: string | null | undefined;\n /** Refetch the bot so the tab reflects the new binding. */\n onWorkflowChanged: () => Promise<void> | void;\n}\n\nexport const BotWorkflowTab: FC<BotWorkflowTabProps> = ({\n botId,\n botName,\n workflowId,\n onWorkflowChanged,\n}) => {\n const t = useTr();\n const { navigateTo } = useBotlit();\n const { createWorkflow } = useCreateWorkflow();\n const [updateBot] = useUpdateBot();\n const [busy, setBusy] = useState(false);\n\n // Resolve by id — `BotApp.workflowId` stores the definition's opaque id, not\n // its workflowKey (which is what the builder route takes). The hook refetches\n // on its own when the bound id changes, so binding/unbinding only has to\n // refresh the bot.\n const { workflow, loading: workflowLoading } = useWorkflowDefinition(\n undefined,\n workflowId ?? undefined\n );\n\n const openBuilder = useCallback(\n (workflowKey: string, version: string) => {\n navigateTo(`workflows/workflow/${workflowKey}/${version || INITIAL_VERSION}`);\n },\n [navigateTo]\n );\n\n const handleDesign = useCallback(async () => {\n setBusy(true);\n try {\n const workflowKey = generateId();\n const name = `${botName} workflow`;\n const created = await createWorkflow({\n workflowKey,\n version: INITIAL_VERSION,\n name,\n description: t(\n 'botlit.botDetail.workflow.createdDescription',\n 'Behaviour designed for this BotManor bot.'\n ),\n definitionJson: buildSeedDefinition(workflowKey, name),\n });\n\n if (!created) {\n throw new Error(\n t('botlit.botDetail.workflow.createError', 'Failed to create the workflow')\n );\n }\n\n await updateBot({ botId, input: { workflowId: created.id } });\n await onWorkflowChanged();\n toast.success(\n t('botlit.botDetail.workflow.createSuccess', 'Workflow created and bound to this bot')\n );\n openBuilder(created.workflowKey, created.version);\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.createError', 'Failed to create the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, botName, createWorkflow, onWorkflowChanged, openBuilder, t, updateBot]);\n\n const handleUnbind = useCallback(async () => {\n if (\n !confirm(\n t(\n 'botlit.botDetail.workflow.unbindConfirm',\n 'Unbind this workflow from the bot? The workflow itself is not deleted.'\n )\n )\n ) {\n return;\n }\n setBusy(true);\n try {\n await updateBot({ botId, input: { workflowId: null } });\n await onWorkflowChanged();\n toast.success(t('botlit.botDetail.workflow.unbindSuccess', 'Workflow unbound'));\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.unbindError', 'Failed to unbind the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, onWorkflowChanged, t, updateBot]);\n\n // ── Not bound ─────────────────────────────────────────────────────────────\n if (!workflowId) {\n return (\n <Card>\n <CardContent className=\"pt-6\">\n <EmptyState\n illustration=\"empty-generic\"\n title={t('botlit.botDetail.workflow.empty.title', 'Design this bot as a workflow')}\n description={t(\n 'botlit.botDetail.workflow.empty.description',\n \"A bot's behaviour is designed as a FluidGrids workflow — the visual canvas where you wire triggers, agents, tools and conditions together. Start one and we will create it, bind it to this bot and open the builder for you.\"\n )}\n action={\n <Button\n leftIcon={<Sparkles size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleDesign()}\n >\n {t('botlit.botDetail.workflow.empty.action', 'Design in workflow builder')}\n </Button>\n }\n />\n </CardContent>\n </Card>\n );\n }\n\n // ── Bound ─────────────────────────────────────────────────────────────────\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Workflow size={18} />\n {t('botlit.botDetail.workflow.bound.title', 'Bound workflow')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.botDetail.workflow.bound.description',\n 'This workflow defines what the bot does when it is invoked.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {workflowLoading ? (\n <div className=\"h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ) : workflow ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.name', 'Name')}\n </p>\n <p className=\"font-medium text-text-primary\">{workflow.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.key', 'Key')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">\n {workflow.workflowKey}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.version', 'Version')}\n </p>\n <Badge variant=\"outline\" className=\"mt-1\">\n {workflow.version}\n </Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.status', 'Status')}\n </p>\n <div className=\"mt-1\">\n <StatusBadge status={workflow.status} />\n </div>\n </div>\n </div>\n ) : (\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.workflowId', 'Workflow ID')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">{workflowId}</p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {t(\n 'botlit.botDetail.workflow.unresolved',\n 'This workflow could not be loaded — it may have been deleted. Unbind it and design a new one.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {workflow && (\n <Button\n leftIcon={<ExternalLink size={16} />}\n disabled={busy}\n onClick={() => openBuilder(workflow.workflowKey, workflow.version)}\n >\n {t('botlit.botDetail.workflow.actions.openBuilder', 'Open in builder')}\n </Button>\n )}\n <Button\n variant=\"outline\"\n leftIcon={<Unlink size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleUnbind()}\n >\n {t('botlit.botDetail.workflow.actions.unbind', 'Unbind')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"BotWorkflowTab.js","names":[],"sources":["../../../src/botlit/pages/BotWorkflowTab.tsx"],"sourcesContent":["/**\n * BotWorkflowTab\n * @module botlit/pages\n *\n * Shown inside BotDetailPage → \"Workflow\" tab.\n *\n * A bot's behaviour is designed as a FluidGrids workflow. `BotApp.workflowId`\n * holds the binding (validated server-side by `assertWorkflowBindingsResolvable`\n * on wspace-botlit-svc), and the FluidGrids builder is already mounted INSIDE\n * BotManor at `workflows/workflow/:id/:version` — so this tab never leaves the\n * product.\n *\n * Flow:\n * 1. Bound → resolve the definition by id (`useWorkflowDefinition`), show\n * name / key / version / status, \"Open in builder\", \"Unbind\".\n * A binding that no longer resolves falls back to the raw id so\n * the user can still clear it.\n * 2. Not bound → zero state whose primary action creates a seeded workflow\n * definition, binds it via `updateBotApp(workflowId)` and drops\n * the user straight into the embedded builder.\n *\n * IMPORTANT — seed graph shape. `BotlitFluidGridsBridge.extractTriggerNodeIds`\n * reads nodes from `definitionJson.data.nodes` (NOT the top level) and treats a\n * node as a trigger when its `type` is `trigger`/`trigger:*`/`*_trigger`, OR its\n * `kind[]` / `data.nodeData.kind[]` contains `trigger`. The seed below uses the\n * workflow service's own BUILTIN manual trigger (`internal:api`, \"Trigger\n * Manually\") — the node the executor resolves as the entry point — and carries\n * `kind: ['trigger', ...]` in both places, so a freshly designed bot is\n * immediately runnable instead of failing with `WORKFLOW_NO_TRIGGER_NODE`.\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useState } from 'react';\nimport { ExternalLink, Sparkles, Unlink, Workflow } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useTr } from '../../shared/hooks/useTr';\nimport {\n useCreateBotWorkflow as useCreateWorkflow,\n useBotWorkflowDefinition as useWorkflowDefinition,\n} from '../hooks/useBotWorkflow';\nimport { Card, CardHeader, CardTitle, CardContent, CardDescription } from '../components/Card';\nimport { Button } from '../components/Button';\nimport { Badge, StatusBadge } from '../components/Badge';\nimport { EmptyState } from '../components/EmptyState';\nimport { useUpdateBot } from '../hooks/useBots';\nimport { useBotlit } from '../providers/BotlitProvider';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Seed graph\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** First version minted for a bot's workflow — matches the builder's own default. */\nconst INITIAL_VERSION = 'v1';\n\n/**\n * BUILTIN \"Trigger Manually\" node (`MANUAL_TRIGGER_MANIFEST` in\n * wspace-workflow-svc). The executor resolves this type as a workflow's entry\n * node, and the builder renders it from the seeded node registry.\n */\nconst MANUAL_TRIGGER_NODE_TYPE = 'internal:api';\nconst MANUAL_TRIGGER_NODE_VERSION = '1.0.0';\nconst MANUAL_TRIGGER_OPERATION = 'onManualTrigger';\nconst MANUAL_TRIGGER_NAME = 'Trigger Manually';\nconst MANUAL_TRIGGER_DESCRIPTION =\n \"Runs the flow when you click 'Test workflow', or when this bot is invoked.\";\n\n/** `kind[]` the BotManor bridge scans for when classifying a node as a trigger. */\nconst MANUAL_TRIGGER_KIND = ['trigger', 'manual', 'entry'];\n\n/** Node shape written into `definitionJson.data.nodes`. */\ntype SeedNode = {\n id: string;\n type: string;\n position: { x: number; y: number };\n /** Top-level kind — the bridge's second trigger-detection path. */\n kind: string[];\n data: {\n operation_name: string;\n operation_type: string;\n version: string;\n nodeData: {\n nodeType: string;\n name: string;\n description: string;\n version: string;\n /** The bridge's third trigger-detection path. */\n kind: string[];\n operations: { name: string; type: string; role: string; description: string }[];\n };\n args: {\n context: { node: { id: string; type: string; kind: string[] } };\n state: Record<string, never>;\n credentials: never[];\n };\n };\n};\n\n/**\n * `definitionJson` document. Mirrors what the builder itself persists\n * (`useSaveWorkflow`) so the graph round-trips through the builder unchanged.\n */\ntype SeedDefinition = {\n key: string;\n name: string;\n description: string;\n workflow_type: string;\n data: {\n id: string;\n workflowKey: string;\n version: string;\n name: string;\n nodes: SeedNode[];\n edges: never[];\n sidebar: { active: string; panels: { nodeProperties: { selectedNode: null } } };\n stickyNotes: never[];\n };\n meta: { creator: string; version: string };\n tags: string[];\n};\n\n/**\n * Generate an opaque id. `crypto.randomUUID` is unavailable on insecure origins\n * and in some test environments, so fall back to a time+random token rather than\n * throwing mid-create.\n */\nfunction generateId(): string {\n const webCrypto = globalThis.crypto as Crypto | undefined;\n if (webCrypto && typeof webCrypto.randomUUID === 'function') {\n return webCrypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Build the starter graph: one manual trigger, nothing else. */\nfunction buildSeedDefinition(workflowKey: string, name: string): SeedDefinition {\n const triggerNode: SeedNode = {\n id: generateId(),\n type: MANUAL_TRIGGER_NODE_TYPE,\n position: { x: 160, y: 160 },\n kind: MANUAL_TRIGGER_KIND,\n data: {\n operation_name: MANUAL_TRIGGER_OPERATION,\n operation_type: 'trigger',\n version: MANUAL_TRIGGER_NODE_VERSION,\n nodeData: {\n nodeType: MANUAL_TRIGGER_NODE_TYPE,\n name: MANUAL_TRIGGER_NAME,\n description: MANUAL_TRIGGER_DESCRIPTION,\n version: MANUAL_TRIGGER_NODE_VERSION,\n kind: MANUAL_TRIGGER_KIND,\n operations: [\n {\n name: MANUAL_TRIGGER_OPERATION,\n type: 'trigger',\n role: 'trigger',\n description: MANUAL_TRIGGER_DESCRIPTION,\n },\n ],\n },\n args: {\n context: {\n node: {\n id: MANUAL_TRIGGER_NODE_TYPE,\n type: MANUAL_TRIGGER_NODE_TYPE,\n kind: MANUAL_TRIGGER_KIND,\n },\n },\n state: {},\n credentials: [],\n },\n },\n };\n\n return {\n key: workflowKey,\n name,\n description: name,\n workflow_type: 'query-conditional',\n data: {\n id: workflowKey,\n workflowKey,\n version: INITIAL_VERSION,\n name,\n nodes: [triggerNode],\n edges: [],\n sidebar: { active: 'store-browse', panels: { nodeProperties: { selectedNode: null } } },\n stickyNotes: [],\n },\n meta: { creator: 'botlit_bot_design', version: INITIAL_VERSION },\n tags: [],\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface BotWorkflowTabProps {\n botId: string;\n botName: string;\n /** `BotApp.workflowId` — the bound workflow definition id, if any. */\n workflowId: string | null | undefined;\n /** Refetch the bot so the tab reflects the new binding. */\n onWorkflowChanged: () => Promise<void> | void;\n}\n\nexport const BotWorkflowTab: FC<BotWorkflowTabProps> = ({\n botId,\n botName,\n workflowId,\n onWorkflowChanged,\n}) => {\n const t = useTr();\n const { navigateTo } = useBotlit();\n const { createWorkflow } = useCreateWorkflow();\n const [updateBot] = useUpdateBot();\n const [busy, setBusy] = useState(false);\n\n // Resolve by id — `BotApp.workflowId` stores the definition's opaque id, not\n // its workflowKey (which is what the builder route takes). The hook refetches\n // on its own when the bound id changes, so binding/unbinding only has to\n // refresh the bot.\n const { workflow, loading: workflowLoading } = useWorkflowDefinition(\n undefined,\n workflowId ?? undefined\n );\n\n const openBuilder = useCallback(\n (workflowKey: string, version: string) => {\n navigateTo(`workflows/workflow/${workflowKey}/${version || INITIAL_VERSION}`);\n },\n [navigateTo]\n );\n\n const handleDesign = useCallback(async () => {\n setBusy(true);\n try {\n const workflowKey = generateId();\n const name = `${botName} workflow`;\n const created = await createWorkflow({\n workflowKey,\n version: INITIAL_VERSION,\n name,\n description: t(\n 'botlit.botDetail.workflow.createdDescription',\n 'Behaviour designed for this BotManor bot.'\n ),\n definitionJson: buildSeedDefinition(workflowKey, name),\n });\n\n if (!created) {\n throw new Error(\n t('botlit.botDetail.workflow.createError', 'Failed to create the workflow')\n );\n }\n\n await updateBot({ botId, input: { workflowId: created.id } });\n await onWorkflowChanged();\n toast.success(\n t('botlit.botDetail.workflow.createSuccess', 'Workflow created and bound to this bot')\n );\n openBuilder(created.workflowKey, created.version);\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.createError', 'Failed to create the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, botName, createWorkflow, onWorkflowChanged, openBuilder, t, updateBot]);\n\n const handleUnbind = useCallback(async () => {\n if (\n !confirm(\n t(\n 'botlit.botDetail.workflow.unbindConfirm',\n 'Unbind this workflow from the bot? The workflow itself is not deleted.'\n )\n )\n ) {\n return;\n }\n setBusy(true);\n try {\n await updateBot({ botId, input: { workflowId: null } });\n await onWorkflowChanged();\n toast.success(t('botlit.botDetail.workflow.unbindSuccess', 'Workflow unbound'));\n } catch (err: unknown) {\n const message =\n err instanceof Error\n ? err.message\n : t('botlit.botDetail.workflow.unbindError', 'Failed to unbind the workflow');\n toast.error(message);\n } finally {\n setBusy(false);\n }\n }, [botId, onWorkflowChanged, t, updateBot]);\n\n // ── Not bound ─────────────────────────────────────────────────────────────\n if (!workflowId) {\n return (\n <Card>\n <CardContent className=\"pt-6\">\n <EmptyState\n illustration=\"empty-generic\"\n title={t('botlit.botDetail.workflow.empty.title', 'Design this bot as a workflow')}\n description={t(\n 'botlit.botDetail.workflow.empty.description',\n \"A bot's behaviour is designed as a FluidGrids workflow — the visual canvas where you wire triggers, agents, tools and conditions together. Start one and we will create it, bind it to this bot and open the builder for you.\"\n )}\n action={\n <Button\n leftIcon={<Sparkles size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleDesign()}\n >\n {t('botlit.botDetail.workflow.empty.action', 'Design in workflow builder')}\n </Button>\n }\n />\n </CardContent>\n </Card>\n );\n }\n\n // ── Bound ─────────────────────────────────────────────────────────────────\n return (\n <div className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <Workflow size={18} />\n {t('botlit.botDetail.workflow.bound.title', 'Bound workflow')}\n </CardTitle>\n <CardDescription>\n {t(\n 'botlit.botDetail.workflow.bound.description',\n 'This workflow defines what the bot does when it is invoked.'\n )}\n </CardDescription>\n </CardHeader>\n <CardContent className=\"space-y-6\">\n {workflowLoading ? (\n <div className=\"h-24 rounded-lg bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ) : workflow ? (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.name', 'Name')}\n </p>\n <p className=\"font-medium text-text-primary\">{workflow.name}</p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.key', 'Key')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">\n {workflow.workflowKey}\n </p>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.version', 'Version')}\n </p>\n <Badge variant=\"outline\" className=\"mt-1\">\n {workflow.version}\n </Badge>\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.status', 'Status')}\n </p>\n <div className=\"mt-1\">\n <StatusBadge status={workflow.status} />\n </div>\n </div>\n </div>\n ) : (\n <div>\n <p className=\"text-sm text-text-secondary\">\n {t('botlit.botDetail.workflow.fields.workflowId', 'Workflow ID')}\n </p>\n <p className=\"mt-1 break-all font-mono text-sm text-text-primary\">{workflowId}</p>\n <p className=\"mt-2 text-sm text-text-secondary\">\n {t(\n 'botlit.botDetail.workflow.unresolved',\n 'This workflow could not be loaded — it may have been deleted. Unbind it and design a new one.'\n )}\n </p>\n </div>\n )}\n\n <div className=\"flex flex-wrap gap-2\">\n {workflow && (\n <Button\n leftIcon={<ExternalLink size={16} />}\n disabled={busy}\n onClick={() => openBuilder(workflow.workflowKey, workflow.version)}\n >\n {t('botlit.botDetail.workflow.actions.openBuilder', 'Open in builder')}\n </Button>\n )}\n <Button\n variant=\"outline\"\n leftIcon={<Unlink size={16} />}\n isLoading={busy}\n disabled={busy}\n onClick={() => void handleUnbind()}\n >\n {t('botlit.botDetail.workflow.actions.unbind', 'Unbind')}\n </Button>\n </div>\n </CardContent>\n </Card>\n </div>\n );\n};\n"],"mappings":"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"}