From 259e931a72246006b8a99d2fc0d5034c6e79325b Mon Sep 17 00:00:00 2001 From: Daisuke Awaji Date: Thu, 4 Dec 2025 16:34:11 +0900 Subject: [PATCH 1/5] feat(agent-builder): add responsive view toggle for editor/preview - Add editor/preview toggle buttons for small screen layouts - Include new translation keys for "editor" and "preview" labels - Import PiPencilSimple and PiEye icons for toggle buttons - Implement activeView state to switch between editor and preview modes - Hide toggle on large screens where both panels are visible --- .../web/public/locales/translation/en.yaml | 2 + .../web/public/locales/translation/ja.yaml | 2 + .../agentBuilder/AgentBuilderEditPage.tsx | 58 ++++++++++++++++--- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/packages/web/public/locales/translation/en.yaml b/packages/web/public/locales/translation/en.yaml index 9ca77c541..4ba73ccec 100644 --- a/packages/web/public/locales/translation/en.yaml +++ b/packages/web/public/locales/translation/en.yaml @@ -40,6 +40,7 @@ agent_builder: description_placeholder: Describe what your agent does... description_too_long: Description must be 500 characters or less edit_agent: Edit Agent + editor: Editor enable_code_execution: Enabling code execution enter_agent_name: Enter the agent name enter_system_prompt: Enter a system prompt that defines the agent behavior @@ -78,6 +79,7 @@ agent_builder: no_mcp_servers_match_filter: No MCP servers match your current filter. no_mcp_servers_selected: No MCP servers selected. Your agent will have basic functionality only. no_public_agents_available: No public agents available + preview: Preview public: Public Agents public_sharing_description: >- Make this agent available on public agent directories and be discovered and diff --git a/packages/web/public/locales/translation/ja.yaml b/packages/web/public/locales/translation/ja.yaml index ecb8e83bf..c83f0dc73 100644 --- a/packages/web/public/locales/translation/ja.yaml +++ b/packages/web/public/locales/translation/ja.yaml @@ -41,6 +41,7 @@ agent_builder: description_placeholder: エージェントの機能を説明してください... description_too_long: 説明は500文字以下である必要があります edit_agent: エージェントを編集 + editor: エディター enable_code_execution: コード実行を有効にする enter_agent_name: エージェント名を入力 enter_system_prompt: エージェントの動作を定義するシステムプロンプトを入力 @@ -76,6 +77,7 @@ agent_builder: no_mcp_servers_match_filter: 現在のフィルターに一致するMCPサーバーがありません。 no_mcp_servers_selected: MCPサーバーが選択されていません。エージェントは基本機能のみ利用できます。 no_public_agents_available: 利用可能な公開エージェントがありません + preview: プレビュー public: 公開エージェント public_sharing_description: >- このエージェントを公開し、他のユーザーが発見して利用できるようにします。エージェントはすべてのユーザーに表示されますが、オリジナルを変更することはできません。 diff --git a/packages/web/src/pages/agentBuilder/AgentBuilderEditPage.tsx b/packages/web/src/pages/agentBuilder/AgentBuilderEditPage.tsx index f56aa2281..7a2df3718 100644 --- a/packages/web/src/pages/agentBuilder/AgentBuilderEditPage.tsx +++ b/packages/web/src/pages/agentBuilder/AgentBuilderEditPage.tsx @@ -8,7 +8,12 @@ import AgentForm, { import AgentTester from '../../components/agentBuilder/AgentTester'; import { useAgentBuilder } from '../../hooks/agentBuilder/useAgentBuilder'; import useAgentBuilderList from '../../hooks/agentBuilder/useAgentBuilderList'; -import { PiRobot as RobotIcon, PiArrowLeft as BackIcon } from 'react-icons/pi'; +import { + PiRobot as RobotIcon, + PiArrowLeft as BackIcon, + PiPencilSimple, + PiEye, +} from 'react-icons/pi'; const AgentBuilderEditPage: React.FC = () => { const { t } = useTranslation(); @@ -26,6 +31,9 @@ const AgentBuilderEditPage: React.FC = () => { null ); + // View toggle state for responsive layout + const [activeView, setActiveView] = useState<'editor' | 'preview'>('editor'); + const handleSave = useCallback( async (formData: AgentFormData) => { if (agentId && isEditMode) { @@ -118,24 +126,55 @@ const AgentBuilderEditPage: React.FC = () => { } return ( -
+
{/* Header */}

{title}

+ + {/* View Toggle for small screens - aligned with title on right */} +
+
+
setActiveView('editor')}> + + + {t('agent_builder.editor')} + +
+
setActiveView('preview')}> + + + {t('agent_builder.preview')} + +
+
+
- {/* Content */} + {/* Content - Large screens: side-by-side, Small screens: toggle view */}
- {/* Agent Configuration */} -
+ {/* Agent Configuration - Always visible on large screens, toggle on small */} +
{ />
- {/* Agent Testing */} + {/* Agent Testing - Always visible on large screens, toggle on small */} {(currentFormData || agent) && ( -
+
Date: Thu, 4 Dec 2025 18:06:54 +0900 Subject: [PATCH 2/5] feat(agent-builder): add AI-powered system prompt generation - Add generate prompt button with streaming AI generation support - Implement overwrite confirmation dialog for existing prompts - Extract MCP server config parsing to shared useMCPServers hook - Add localization strings for prompt generation UI (en/ja) --- .../web/public/locales/translation/en.yaml | 6 + .../web/public/locales/translation/ja.yaml | 6 + .../src/components/agentBuilder/AgentForm.tsx | 124 +++++++++++-- .../agentBuilder/MCPServerManager.tsx | 29 +--- packages/web/src/hooks/useMCPServers.ts | 48 ++++++ packages/web/src/hooks/usePromptGeneration.ts | 163 ++++++++++++++++++ .../src/prompts/agentSystemPromptGenerator.ts | 54 ++++++ packages/web/src/utils/streamParser.ts | 77 +++++++++ 8 files changed, 470 insertions(+), 37 deletions(-) create mode 100644 packages/web/src/hooks/useMCPServers.ts create mode 100644 packages/web/src/hooks/usePromptGeneration.ts create mode 100644 packages/web/src/prompts/agentSystemPromptGenerator.ts create mode 100644 packages/web/src/utils/streamParser.ts diff --git a/packages/web/public/locales/translation/en.yaml b/packages/web/public/locales/translation/en.yaml index 4ba73ccec..56a7af118 100644 --- a/packages/web/public/locales/translation/en.yaml +++ b/packages/web/public/locales/translation/en.yaml @@ -60,6 +60,9 @@ agent_builder: failed_to_update_agent: Failed to update agent favorites: Favorites filter_by_tag: Filter by tag + generate_short: Generate + generate_with_ai: Generate with AI + generating_prompt: Generating system prompt... loading_agent: Loading agent... mcp_server_configuration: MCP Server Configuration mcp_server_description: >- @@ -79,6 +82,9 @@ agent_builder: no_mcp_servers_match_filter: No MCP servers match your current filter. no_mcp_servers_selected: No MCP servers selected. Your agent will have basic functionality only. no_public_agents_available: No public agents available + overwrite_confirm: Overwrite + overwrite_prompt_message: A system prompt already exists. Do you want to overwrite it with AI-generated prompt? + overwrite_prompt_title: Overwrite System Prompt Confirmation preview: Preview public: Public Agents public_sharing_description: >- diff --git a/packages/web/public/locales/translation/ja.yaml b/packages/web/public/locales/translation/ja.yaml index c83f0dc73..69dc2fa4c 100644 --- a/packages/web/public/locales/translation/ja.yaml +++ b/packages/web/public/locales/translation/ja.yaml @@ -60,6 +60,9 @@ agent_builder: failed_to_update_agent: エージェントの更新に失敗しました favorites: お気に入り filter_by_tag: タグでフィルター + generate_short: 生成 + generate_with_ai: AIにより生成する + generating_prompt: システムプロンプトを生成中... loading_agent: エージェントを読み込み中... mcp_server_configuration: MCPサーバー設定 mcp_server_description: エージェントに追加機能を提供するMCPサーバーを選択してください。これらのサーバーはセキュリティのため管理者によって事前設定されています。 @@ -77,6 +80,9 @@ agent_builder: no_mcp_servers_match_filter: 現在のフィルターに一致するMCPサーバーがありません。 no_mcp_servers_selected: MCPサーバーが選択されていません。エージェントは基本機能のみ利用できます。 no_public_agents_available: 利用可能な公開エージェントがありません + overwrite_confirm: 上書きする + overwrite_prompt_message: すでにシステムプロンプトが入力されています。AIで生成したプロンプトで上書きしますか? + overwrite_prompt_title: システムプロンプトの上書き確認 preview: プレビュー public: 公開エージェント public_sharing_description: >- diff --git a/packages/web/src/components/agentBuilder/AgentForm.tsx b/packages/web/src/components/agentBuilder/AgentForm.tsx index b834fc127..91a934a96 100644 --- a/packages/web/src/components/agentBuilder/AgentForm.tsx +++ b/packages/web/src/components/agentBuilder/AgentForm.tsx @@ -1,19 +1,24 @@ import React, { useState, useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import Button from '../Button'; +import ButtonIcon from '../ButtonIcon'; import InputText from '../InputText'; import Textarea from '../Textarea'; import Select from '../Select'; import MCPServerManager from './MCPServerManager'; +import ModalDialog from '../ModalDialog'; import { MODELS } from '../../hooks/useModel'; import { AgentConfiguration } from 'generative-ai-use-cases'; +import usePromptGeneration from '../../hooks/usePromptGeneration'; +import useMCPServers from '../../hooks/useMCPServers'; +import { PiSparkle, PiStop } from 'react-icons/pi'; export interface AgentFormData { name: string; description: string; systemPrompt: string; modelId: string; - mcpServers: string[]; // Changed to string array + mcpServers: string[]; codeExecutionEnabled: boolean; isPublic: boolean; tags: string[]; @@ -55,6 +60,31 @@ const AgentForm: React.FC = ({ }); const [tagsInput, setTagsInput] = useState(''); + const [showOverwriteDialog, setShowOverwriteDialog] = useState(false); + + // Load MCP server configs using the shared hook + const mcpServerConfigs = useMCPServers(); + + // Use the prompt generation hook + const { + generatedPrompt, + isGenerating, + generate: generatePrompt, + cancel: cancelGeneration, + } = usePromptGeneration({ + modelId: formData.modelId, + agentName: formData.name, + agentDescription: formData.description, + mcpServers: formData.mcpServers, + mcpServerConfigs, + }); + + // Update systemPrompt when generation produces new content + useEffect(() => { + if (generatedPrompt) { + setFormData((prev) => ({ ...prev, systemPrompt: generatedPrompt })); + } + }, [generatedPrompt]); // Update formData.modelId when availableModels becomes available useEffect(() => { @@ -86,7 +116,6 @@ const AgentForm: React.FC = ({ // Notify parent component when form data changes useEffect(() => { if (onFormDataChange) { - // Parse tags from input for real-time updates const tags = tagsInput .split(',') .map((tag) => tag.trim()) @@ -103,7 +132,6 @@ const AgentForm: React.FC = ({ const handleSave = useCallback(async () => { try { - // Parse tags from input const tags = tagsInput .split(',') .map((tag) => tag.trim()) @@ -115,11 +143,34 @@ const AgentForm: React.FC = ({ }; await onSave(agentData); - } catch (error) { - console.error('Error saving agent:', error); + } catch (err) { + console.error('Error saving agent:', err); } }, [formData, tagsInput, onSave]); + const handleGenerateClick = useCallback(() => { + if (formData.systemPrompt.trim()) { + setShowOverwriteDialog(true); + } else { + setFormData((prev) => ({ ...prev, systemPrompt: '' })); + generatePrompt(); + } + }, [formData.systemPrompt, generatePrompt]); + + const handleConfirmOverwrite = useCallback(() => { + setShowOverwriteDialog(false); + setFormData((prev) => ({ ...prev, systemPrompt: '' })); + generatePrompt(); + }, [generatePrompt]); + + const handleCancelGeneration = useCallback(() => { + cancelGeneration(); + }, [cancelGeneration]); + + // Check if generate button should be disabled + const isGenerateDisabled = + !formData.name.trim() || !formData.description.trim() || loading; + const isFormValid = formData.name && formData.systemPrompt && formData.modelId; @@ -202,10 +253,33 @@ const AgentForm: React.FC = ({ {/* System Prompt */}
- {/* eslint-disable-next-line @shopify/jsx-no-hardcoded-content */} -

- {t('agent_builder.system_prompt')} {'*'} -

+
+ {/* eslint-disable-next-line @shopify/jsx-no-hardcoded-content */} +

+ {t('agent_builder.system_prompt')} {'*'} +

+
+ {isGenerating ? ( + + + + ) : ( + + )} +
+