├── .bedrock-engineer ├── agents │ └── developer-for-bedrock-engineer.yaml └── rules │ └── add-tool-instruction.md ├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── ISSUE_TEMPLATE │ └── feature_request.md └── workflows │ └── build.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.yaml ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README-ja.md ├── README.md ├── assets ├── agent-chat-diagram.png ├── agent-chat-search.png ├── agent-directory.png ├── custom-agents.png ├── custom-tools.png ├── diagram-generator.png ├── select-agents.png ├── select-tools.png ├── step-functions-generator.png ├── voice-chat-page.png ├── website-generator-data-visualization.png ├── website-generator-healthcare.png └── website-generator.png ├── build ├── entitlements.mac.plist ├── icon.icns ├── icon.ico ├── icon.iconset │ ├── README.md │ ├── icon_128x128.png │ ├── icon_128x128@2x.png │ ├── icon_16x16.png │ ├── icon_16x16@2x.png │ ├── icon_256x256.png │ ├── icon_256x256@2x.png │ ├── icon_32x32.png │ ├── icon_32x32@2x.png │ ├── icon_512x512.png │ └── icon_512x512@2x.png ├── icon.png └── make-icon.sh ├── dev-app-update.yml ├── electron-builder.yml ├── electron.vite.config.ts ├── jest.config.js ├── jest.integration.config.js ├── jest.integration.setup.js ├── package-lock.json ├── package.json ├── src ├── common │ └── logger │ │ ├── config.ts │ │ ├── formatters.ts │ │ ├── index.ts │ │ └── transports │ │ ├── console.ts │ │ └── file.ts ├── main │ ├── api │ │ ├── bedrock │ │ │ ├── __tests__ │ │ │ │ ├── agentService.integration.test.ts │ │ │ │ ├── flowService.integration.test.ts │ │ │ │ ├── guardrailService.integration.test.ts │ │ │ │ ├── imageService.integration.test.ts │ │ │ │ └── test-assets │ │ │ │ │ └── icon.png │ │ │ ├── client.ts │ │ │ ├── index.ts │ │ │ ├── models.ts │ │ │ ├── services │ │ │ │ ├── agentService.ts │ │ │ │ ├── converseService.ts │ │ │ │ ├── flowService.ts │ │ │ │ ├── guardrailService.ts │ │ │ │ ├── imageRecognitionService.ts │ │ │ │ ├── imageService.ts │ │ │ │ ├── index.ts │ │ │ │ ├── modelService.ts │ │ │ │ └── translateService.ts │ │ │ ├── types.ts │ │ │ ├── types │ │ │ │ ├── claude.ts │ │ │ │ └── image.ts │ │ │ └── utils │ │ │ │ ├── awsUtils.ts │ │ │ │ └── imageUtils.ts │ │ ├── command │ │ │ ├── commandService.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ └── sonic │ │ │ ├── SONIC_TOOL_INTEGRATION.md │ │ │ ├── client.ts │ │ │ ├── consts.ts │ │ │ ├── tool-executor │ │ │ ├── SonicToolExecutor.ts │ │ │ └── index.ts │ │ │ └── types.ts │ ├── handlers │ │ ├── agent-handlers.ts │ │ ├── bedrock-handlers.ts │ │ ├── file-handlers.ts │ │ ├── util-handlers.ts │ │ └── window-handlers.ts │ ├── index.ts │ ├── lib │ │ └── ipc-handler.ts │ └── store │ │ └── chatSession.ts ├── preload │ ├── api.ts │ ├── appWindow.ts │ ├── chat-history.ts │ ├── file.ts │ ├── helpers │ │ └── agent-helpers.ts │ ├── index.ts │ ├── ipc-client.ts │ ├── lib │ │ ├── contentChunker.ts │ │ ├── gitignore-like-matcher.test.ts │ │ ├── gitignore-like-matcher.ts │ │ ├── line-range-utils.ts │ │ └── random-port.ts │ ├── logger.ts │ ├── mcp │ │ ├── claude_desktop_config.sample.json │ │ ├── command-resolver.ts │ │ ├── index.integration.test.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── mcp-client.integration.test.ts │ │ └── mcp-client.ts │ ├── store.ts │ └── tools │ │ ├── base │ │ ├── BaseTool.ts │ │ ├── errors.ts │ │ └── types.ts │ │ ├── common │ │ ├── Logger.ts │ │ ├── StoreManager.ts │ │ └── ToolMetadataHelper.ts │ │ ├── handlers │ │ ├── bedrock │ │ │ ├── GenerateImageTool.ts │ │ │ ├── InvokeBedrockAgentTool.ts │ │ │ ├── InvokeFlowTool.ts │ │ │ ├── RecognizeImageTool.ts │ │ │ ├── RetrieveTool.ts │ │ │ └── index.ts │ │ ├── command │ │ │ ├── ExecuteCommandTool.ts │ │ │ └── index.ts │ │ ├── filesystem │ │ │ ├── ApplyDiffEditTool.ts │ │ │ ├── CopyFileTool.ts │ │ │ ├── CreateFolderTool.ts │ │ │ ├── ListFilesTool.ts │ │ │ ├── MoveFileTool.ts │ │ │ ├── ReadFilesTool.ts │ │ │ ├── WriteToFileTool.ts │ │ │ └── index.ts │ │ ├── interpreter │ │ │ ├── CodeInterpreterTool.integration.test.ts │ │ │ ├── CodeInterpreterTool.test.ts │ │ │ ├── CodeInterpreterTool.ts │ │ │ ├── DockerExecutor.integration.test.ts │ │ │ ├── DockerExecutor.test.ts │ │ │ ├── DockerExecutor.ts │ │ │ ├── FileManager.ts │ │ │ ├── SecurityManager.ts │ │ │ ├── TaskManager.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── mcp │ │ │ ├── McpToolAdapter.ts │ │ │ └── index.ts │ │ ├── thinking │ │ │ ├── ThinkTool.ts │ │ │ └── index.ts │ │ └── web │ │ │ ├── FetchWebsiteTool.ts │ │ │ ├── TavilySearchTool.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ └── registry.ts ├── renderer │ ├── index.css │ ├── index.html │ ├── public │ │ └── worklets │ │ │ └── audio-player-processor.js │ └── src │ │ ├── App.tsx │ │ ├── assets │ │ ├── base.css │ │ ├── directory-agents │ │ │ ├── amazon-bedrock-agents-builder.yaml │ │ │ ├── aws-cost-analyzer.yaml │ │ │ ├── aws-document-researcher.yaml │ │ │ ├── aws-resource-explorer.yaml │ │ │ ├── data-analyst.yaml │ │ │ ├── developer-for-bedrock-engineer.yaml │ │ │ ├── github-implement-planner.yaml │ │ │ ├── github-pull-request-reviewer.yaml │ │ │ ├── japanese-english-lesson.yaml │ │ │ ├── knowledge-base-rag-agent.yaml │ │ │ ├── nova-canvas-agent.yaml │ │ │ ├── nova-sonic-voice-chat.yaml │ │ │ ├── picture-books-creator.yaml │ │ │ ├── playwright-browser-use.yaml │ │ │ ├── room-prompt-engineer.yaml │ │ │ ├── senior-frontend-developer.yaml │ │ │ ├── simulation-engineer.yaml │ │ │ └── web-deepsearcher.yaml │ │ ├── images │ │ │ └── icons │ │ │ │ └── ai.svg │ │ ├── lottie │ │ │ ├── loading-database.json │ │ │ ├── loading-dots.json │ │ │ ├── loading-voice-with-ai.json │ │ │ └── loading-website.json │ │ └── main.css │ │ ├── command-palette.tsx │ │ ├── components │ │ ├── DeepSearchButton.tsx │ │ ├── JSONViewer │ │ │ ├── JSONEditor.tsx │ │ │ └── index.tsx │ │ ├── Loader.tsx │ │ ├── LocalImage │ │ │ └── index.tsx │ │ ├── Markdown │ │ │ ├── MD.tsx │ │ │ ├── styles.module.css │ │ │ └── styles.module.css.d.ts │ │ ├── Versions.tsx │ │ ├── ViewToggleButton.tsx │ │ ├── VoiceAI │ │ │ ├── VoiceAILottie.tsx │ │ │ └── index.ts │ │ ├── WebLoader.tsx │ │ ├── common │ │ │ └── MonacoJSONEditor.tsx │ │ └── icons │ │ │ ├── AgentIcons.tsx │ │ │ └── ToolIcons.tsx │ │ ├── constants │ │ ├── defaultToolSets.ts │ │ └── voiceIds.ts │ │ ├── contexts │ │ ├── AgentDirectoryContext.tsx │ │ ├── ChatHistoryContext.tsx │ │ ├── SettingsContext.tsx │ │ └── WebsiteGeneratorContext.tsx │ │ ├── hooks │ │ ├── use-debounse.ts │ │ ├── useAutoScroll.ts │ │ ├── useChat.ts │ │ ├── useModal.tsx │ │ ├── useScroll.ts │ │ ├── useSetting.ts │ │ ├── useTheme.ts │ │ └── useWebsiteGeneratorSetting.ts │ │ ├── i18n │ │ ├── config.ts │ │ └── locales │ │ │ ├── agentDirectory │ │ │ ├── en.ts │ │ │ ├── index.ts │ │ │ └── ja.ts │ │ │ ├── awsDiagramGenerator │ │ │ └── index.ts │ │ │ ├── chat │ │ │ ├── agent.ts │ │ │ ├── examples.ts │ │ │ ├── guardrails.ts │ │ │ ├── history.ts │ │ │ ├── index.ts │ │ │ ├── messages.ts │ │ │ └── tools.ts │ │ │ ├── en.ts │ │ │ ├── ja.ts │ │ │ ├── planActMode.ts │ │ │ ├── settings │ │ │ ├── agentSettings.ts │ │ │ ├── agentToolsSettings.ts │ │ │ ├── bedrock │ │ │ │ └── index.ts │ │ │ ├── iamPolicy.ts │ │ │ ├── index.ts │ │ │ ├── lightModelSettings.ts │ │ │ ├── notification.ts │ │ │ ├── promptCache.ts │ │ │ └── tokenAnalytics.ts │ │ │ └── thinkingMode.ts │ │ ├── lib │ │ ├── api.ts │ │ ├── contextLength │ │ │ ├── __tests__ │ │ │ │ └── index.test.ts │ │ │ └── index.ts │ │ ├── modelSelection.ts │ │ ├── pricing │ │ │ ├── modelPricing.test.ts │ │ │ └── modelPricing.ts │ │ ├── promptCacheUtils.ts │ │ └── util.ts │ │ ├── main.tsx │ │ ├── pages │ │ ├── AgentDirectoryPage │ │ │ ├── AgentDirectoryPage.tsx │ │ │ ├── components │ │ │ │ ├── AgentDetailModal.tsx │ │ │ │ ├── AgentList.tsx │ │ │ │ ├── ContributorModal │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useContributorModal.tsx │ │ │ │ └── TagFilter.tsx │ │ │ └── index.ts │ │ ├── ChatPage │ │ │ ├── ChatPage.tsx │ │ │ ├── components │ │ │ │ ├── AgentForm │ │ │ │ │ ├── AgentForm.tsx │ │ │ │ │ ├── BasicSection.tsx │ │ │ │ │ ├── BedrockAgentsSection.tsx │ │ │ │ │ ├── CommandsSection.tsx │ │ │ │ │ ├── KnowledgeBasesSection.tsx │ │ │ │ │ ├── McpServerSection │ │ │ │ │ │ ├── ConnectionTestResults.tsx │ │ │ │ │ │ ├── McpServerForm.tsx │ │ │ │ │ │ ├── McpServerList.tsx │ │ │ │ │ │ ├── ServerListItem.tsx │ │ │ │ │ │ ├── hooks │ │ │ │ │ │ │ └── useMcpServerState.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── types │ │ │ │ │ │ │ └── mcpServer.types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── connectionTestUtils.ts │ │ │ │ │ │ │ ├── eventUtils.ts │ │ │ │ │ │ │ └── mcpServerUtils.ts │ │ │ │ │ ├── ScenariosSection.tsx │ │ │ │ │ ├── SystemPromptSection.tsx │ │ │ │ │ ├── TagsSection.tsx │ │ │ │ │ ├── ToolsSection │ │ │ │ │ │ ├── ToolsSection.tsx │ │ │ │ │ │ ├── ToolsSectionContainer.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── AvailableToolsTab │ │ │ │ │ │ │ │ ├── CategorySelector.tsx │ │ │ │ │ │ │ │ ├── ToolCategorySection.tsx │ │ │ │ │ │ │ │ ├── ToolItem.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── DetailsTab │ │ │ │ │ │ │ │ ├── BedrockAgentsContent.tsx │ │ │ │ │ │ │ │ ├── CommandsContent.tsx │ │ │ │ │ │ │ │ ├── FlowsContent.tsx │ │ │ │ │ │ │ │ ├── KnowledgeBasesContent.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── ToolInfoModal.tsx │ │ │ │ │ │ ├── hooks │ │ │ │ │ │ │ ├── useMcpToolsIntegration.ts │ │ │ │ │ │ │ ├── useToolsFormatter.ts │ │ │ │ │ │ │ └── useToolsState.ts │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── eventUtils.ts │ │ │ │ │ │ │ ├── toolCategories.ts │ │ │ │ │ │ │ └── toolFilters.ts │ │ │ │ │ ├── components │ │ │ │ │ │ ├── AgentFormContent.tsx │ │ │ │ │ │ ├── AgentFormSidebar.tsx │ │ │ │ │ │ ├── AgentFormTabs.tsx │ │ │ │ │ │ └── FormActionButtons.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── types │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── useAgentForm.ts │ │ │ │ │ ├── usePromptGeneration.ts │ │ │ │ │ └── utils │ │ │ │ │ │ └── formEventUtils.ts │ │ │ │ ├── AgentList │ │ │ │ │ ├── AgentCard.tsx │ │ │ │ │ ├── AgentList.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── useAgentFilter.ts │ │ │ │ ├── AgentSelector │ │ │ │ │ └── index.tsx │ │ │ │ ├── ChatHistory │ │ │ │ │ └── index.tsx │ │ │ │ ├── Code │ │ │ │ │ ├── CodeRenderer.tsx │ │ │ │ │ └── Mermaid.tsx │ │ │ │ ├── CodeBlocks │ │ │ │ │ ├── BedrockAgent │ │ │ │ │ │ └── BedrockAgentResult.tsx │ │ │ │ │ ├── CodeInterpreter │ │ │ │ │ │ ├── CodeInterpreterResult.tsx │ │ │ │ │ │ ├── ErrorDisplay.tsx │ │ │ │ │ │ ├── ExecutedCodeBlock.tsx │ │ │ │ │ │ ├── ExecutionMetadata.tsx │ │ │ │ │ │ ├── FileDisplay.tsx │ │ │ │ │ │ ├── ImagePreview.tsx │ │ │ │ │ │ ├── OutputDisplay.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── ExecuteCommand │ │ │ │ │ │ └── ExecuteCommandResult.tsx │ │ │ │ │ ├── GenerateImage │ │ │ │ │ │ └── GenerateImageResult.tsx │ │ │ │ │ ├── GuardContent │ │ │ │ │ │ ├── GuardContent.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── JSONCodeBlock.tsx │ │ │ │ │ ├── Reasoning │ │ │ │ │ │ └── ReasoningContent.tsx │ │ │ │ │ ├── RecognizeImage │ │ │ │ │ │ └── RecognizeImageResult.tsx │ │ │ │ │ ├── RetrievalResult │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── TavilySearch │ │ │ │ │ │ ├── SearchImage.tsx │ │ │ │ │ │ ├── SearchResult.tsx │ │ │ │ │ │ └── TavilySearchResult.tsx │ │ │ │ │ └── TextCodeBlock.tsx │ │ │ │ ├── CodeInterpreter │ │ │ │ │ ├── AsyncTaskCard.tsx │ │ │ │ │ └── TaskListCard.tsx │ │ │ │ ├── ExampleScenarios │ │ │ │ │ └── index.tsx │ │ │ │ ├── InputForm │ │ │ │ │ ├── DirectorySelector.tsx │ │ │ │ │ ├── PlanActToggle.tsx │ │ │ │ │ ├── TextArea.tsx │ │ │ │ │ ├── ToolSettings.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── InputFormContainer │ │ │ │ │ └── index.tsx │ │ │ │ ├── InterleaveThinkingToggle │ │ │ │ │ └── index.tsx │ │ │ │ ├── MessageList │ │ │ │ │ ├── Avatar.tsx │ │ │ │ │ ├── Message.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── MetadataViewer │ │ │ │ │ ├── MetadataViewer.tsx │ │ │ │ │ ├── StructuredJsonView.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── ModelSelector │ │ │ │ │ ├── claude-color.svg │ │ │ │ │ ├── deepseek-color.svg │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── meta-color.svg │ │ │ │ │ └── nova-color.svg │ │ │ │ ├── Recommendations │ │ │ │ │ └── index.tsx │ │ │ │ ├── ThinkingModeSelector │ │ │ │ │ └── index.tsx │ │ │ │ └── Tool │ │ │ │ │ └── ToolIcons.tsx │ │ │ ├── constants │ │ │ │ ├── AGENTS_ENVIRONMENT_CONTEXT.ts │ │ │ │ └── DEFAULT_AGENTS.ts │ │ │ ├── hooks │ │ │ │ ├── useAgentChat.ts │ │ │ │ ├── useAgentTools.ts │ │ │ │ └── useScenarioGenerator.ts │ │ │ ├── modals │ │ │ │ ├── useAgentSettingsModal.tsx │ │ │ │ ├── useIgnoreFileModal.tsx │ │ │ │ ├── useSystemPromptModal.tsx │ │ │ │ ├── useTokenAnalyticsModal.tsx │ │ │ │ └── useToolSettingModal │ │ │ │ │ ├── BedrockAgentSettingForm.tsx │ │ │ │ │ ├── CodeInterpreterSettingForm.tsx │ │ │ │ │ ├── CommandForm.tsx │ │ │ │ │ ├── FlowSettingForm.tsx │ │ │ │ │ ├── GenerateImageSettingForm.tsx │ │ │ │ │ ├── KnowledgeBaseSettingForm.tsx │ │ │ │ │ ├── PlanModeCompatibilityBadge.tsx │ │ │ │ │ ├── RecognizeImageSettingForm.tsx │ │ │ │ │ ├── TavilySearchSettingForm.tsx │ │ │ │ │ ├── ThinkToolSettingForm.tsx │ │ │ │ │ ├── ToolSpecJsonModal.tsx │ │ │ │ │ └── index.tsx │ │ │ └── utils │ │ │ │ ├── placeholder.ts │ │ │ │ └── titleGenerator.ts │ │ ├── DiagramGeneratorPage │ │ │ ├── DiagramGeneratorPage.tsx │ │ │ ├── components │ │ │ │ ├── LoaderWithReasoning.tsx │ │ │ │ ├── ReasoningTextDisplay.tsx │ │ │ │ └── RecommendDiagrams.tsx │ │ │ ├── example-diagrams.tsx │ │ │ ├── hooks │ │ │ │ └── useRecommendDiagrams.tsx │ │ │ └── utils │ │ │ │ ├── __tests__ │ │ │ │ └── xmlParser.test.ts │ │ │ │ └── xmlParser.ts │ │ ├── ErrorPage │ │ │ └── ErrorPage.tsx │ │ ├── HomePage │ │ │ ├── HomePage.tsx │ │ │ └── Robot.json │ │ ├── SettingPage │ │ │ ├── SettingPage.tsx │ │ │ ├── components │ │ │ │ ├── IAMPolicyModal.tsx │ │ │ │ ├── LightModelSettings.tsx │ │ │ │ ├── SettingInput.tsx │ │ │ │ ├── SettingSection.tsx │ │ │ │ ├── SettingSelect.tsx │ │ │ │ ├── ThinkingModeSettings.tsx │ │ │ │ └── sections │ │ │ │ │ ├── AWSSection.tsx │ │ │ │ │ ├── AdvancedSection.tsx │ │ │ │ │ ├── AgentChatSection.tsx │ │ │ │ │ ├── ConfigDirSection.tsx │ │ │ │ │ ├── GuardrailSettings.tsx │ │ │ │ │ ├── LanguageSection.tsx │ │ │ │ │ ├── NotificationSection.tsx │ │ │ │ │ ├── ProjectSection.tsx │ │ │ │ │ └── index.ts │ │ │ └── types │ │ │ │ └── index.ts │ │ ├── SpeakPage │ │ │ ├── components │ │ │ │ ├── AIIcon.tsx │ │ │ │ ├── AudioControls.tsx │ │ │ │ ├── ChatDisplay.tsx │ │ │ │ ├── ConnectionStatus.tsx │ │ │ │ ├── PermissionHelpModal │ │ │ │ │ ├── index.ts │ │ │ │ │ └── usePermissionHelpModal.tsx │ │ │ │ ├── SampleTextCarousel.tsx │ │ │ │ ├── ThinkingIndicator.tsx │ │ │ │ ├── ToolResultDisplay.tsx │ │ │ │ ├── TranslatedMessage.tsx │ │ │ │ └── VoiceSelector │ │ │ │ │ ├── VoiceSelector.tsx │ │ │ │ │ ├── VoiceVisual.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── index.tsx │ │ │ ├── constants │ │ │ │ ├── translationLanguages.ts │ │ │ │ └── voices.ts │ │ │ ├── hooks │ │ │ │ ├── useAudioPlayer.ts │ │ │ │ ├── useAudioRecorder.ts │ │ │ │ ├── useSocketConnection.ts │ │ │ │ ├── useSpeakChat.ts │ │ │ │ └── useTranslation.ts │ │ │ ├── index.tsx │ │ │ ├── lib │ │ │ │ ├── AudioPlayer.ts │ │ │ │ ├── AudioPlayerProcessor.worklet.ts │ │ │ │ ├── ChatHistoryManager.ts │ │ │ │ └── ObjectsExt.ts │ │ │ └── modals │ │ │ │ └── useSystemPromptModal.tsx │ │ ├── StepFunctionsGeneratorPage │ │ │ ├── ASLEditor.tsx │ │ │ ├── SAMPLE_ASL.tsx │ │ │ ├── StepFunctionsGeneratorPage.tsx │ │ │ └── aws-sfn-graph.d.ts │ │ └── WebsiteGeneratorPage │ │ │ ├── DEFAULT_CODES.tsx │ │ │ ├── LazyVisibleMessage.tsx │ │ │ ├── LoadingDataBase.lottie.tsx │ │ │ ├── LoadingDots.lottie.tsx │ │ │ ├── LoadingWebsite.lottie.tsx │ │ │ ├── VoiceAI.lottie.tsx │ │ │ ├── WebsiteGeneratorPage.tsx │ │ │ ├── components │ │ │ ├── KnowledgeBaseConnectButton.tsx │ │ │ ├── LoaderWithReasoning.tsx │ │ │ ├── Preview.tsx │ │ │ ├── RagLoader.tsx │ │ │ ├── ReasoningTextDisplay.tsx │ │ │ ├── RecommendChanges.tsx │ │ │ ├── StyleSelector.tsx │ │ │ └── TemplateButton.tsx │ │ │ ├── hooks │ │ │ └── useRecommendChanges.tsx │ │ │ ├── templates.tsx │ │ │ ├── useDataSourceConnectModal.tsx │ │ │ └── util.ts │ │ ├── prompts │ │ ├── diagram-prompt.ts │ │ └── prompts.ts │ │ ├── routes.tsx │ │ ├── services │ │ └── NotificationService.ts │ │ └── types │ │ └── images.d.ts ├── test │ ├── sandbox │ │ └── sts.client.test.ts │ └── src │ │ └── preload │ │ └── tools.test.ts └── types │ ├── agent-chat.ts │ ├── agent.ts │ ├── aws-regions.ts │ ├── chat │ ├── history.ts │ ├── message.ts │ └── metadata.ts │ ├── electron.ts │ ├── ipc.ts │ ├── llm.ts │ ├── plan-mode-tools.ts │ ├── preload │ └── index.ts │ └── tools.ts ├── tailwind.config.js ├── tsconfig.json ├── tsconfig.node.json ├── tsconfig.test.json └── tsconfig.web.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # AWS Credentials 2 | AWS_ACCESS_KEY_ID=your_access_key_here 3 | AWS_SECRET_ACCESS_KEY=your_secret_key_here 4 | AWS_REGION=us-east-1 5 | 6 | # Test Configuration 7 | INTEGRATION_TEST=true 8 | 9 | # Example of how to use these environment variables 10 | # 1. Copy this file to .env 11 | # 2. Replace the placeholder values with your actual credentials 12 | # 3. Run npm run test:integration -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | out 4 | .gitignore 5 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'eslint:recommended', 4 | 'plugin:react/recommended', 5 | 'plugin:react/jsx-runtime', 6 | '@electron-toolkit/eslint-config-ts/recommended', 7 | '@electron-toolkit/eslint-config-prettier' 8 | ], 9 | settings: { 10 | react: { 11 | version: 'detect' // React のバージョンを自動検出 12 | } 13 | }, 14 | rules: { 15 | '@typescript-eslint/explicit-function-return-type': 'off', 16 | '@typescript-eslint/no-explicit-any': 'off', 17 | '@typescript-eslint/no-unused-vars': [ 18 | 'error', 19 | { argsIgnorePattern: '^_', varsIgnorePattern: '^_' } 20 | ], 21 | 'react/prop-types': 'off', 22 | 'no-control-regex': 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE REQUEST] " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Is your feature request related to a problem? / この機能リクエストは何か問題に関連していますか? 11 | 12 | **English** 13 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 14 | 15 | **日本語** 16 | 問題の内容を簡潔に説明してください。例:「いつも〜の時に困っています」 17 | 18 | ## Describe the solution you'd like / 希望する解決策を説明してください。 19 | 20 | **English** 21 | A clear and concise description of what you want to happen. 22 | 23 | **日本語** 24 | どのようなことが実現されることを望むのか、具体的に説明してください。 25 | 26 | ## Describe alternatives you've considered / 検討した代替案について説明してください。 27 | 28 | **English** 29 | A clear and concise description of any alternative solutions or features you've considered. 30 | 31 | **日本語** 32 | 検討した他の解決策や機能について簡潔に説明してください。 33 | 34 | ## Additional context / 補足情報 35 | 36 | **English** 37 | Add any other context or screenshots about the feature request here. 38 | 39 | **日本語** 40 | 機能リクエストに関する他の情報やスクリーンショットがあれば、ここに追加してください。 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: ['**'] 6 | 7 | jobs: 8 | build: 9 | strategy: 10 | matrix: 11 | os: [macos-latest, windows-latest] 12 | 13 | runs-on: ${{ matrix.os }} 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Use Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 20 21 | 22 | - name: Install dependencies 23 | run: npm ci 24 | 25 | - name: Lint 26 | run: npm run lint 27 | 28 | - name: Run unit tests 29 | run: npm test -- --coverage 30 | 31 | - name: Build app 32 | run: npm run build:${{ matrix.os == 'windows-latest' && 'win' || 'mac' }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | out 4 | .DS_Store 5 | *.log* 6 | .env 7 | 8 | ash_output/ 9 | .bedrock-engineer/workspaces/ 10 | 11 | test-outputs 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | pnpm-lock.yaml 4 | LICENSE.md 5 | tsconfig.json 6 | tsconfig.*.json 7 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | singleQuote: true 2 | semi: false 3 | printWidth: 100 4 | trailingComma: none 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "lokalise.i18n-ally"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug Main Process", 6 | "type": "node", 7 | "request": "launch", 8 | "cwd": "${workspaceRoot}", 9 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite", 10 | "windows": { 11 | "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd" 12 | }, 13 | "runtimeArgs": ["--sourcemap"], 14 | "env": { 15 | "REMOTE_DEBUGGING_PORT": "9222" 16 | } 17 | }, 18 | { 19 | "name": "Debug Renderer Process", 20 | "port": 9222, 21 | "request": "attach", 22 | "type": "chrome", 23 | "webRoot": "${workspaceFolder}/src/renderer", 24 | "timeout": 60000, 25 | "presentation": { 26 | "hidden": true 27 | } 28 | } 29 | ], 30 | "compounds": [ 31 | { 32 | "name": "Debug All", 33 | "configurations": ["Debug Main Process", "Debug Renderer Process"], 34 | "presentation": { 35 | "order": 1 36 | } 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[typescript]": { 3 | "editor.defaultFormatter": "esbenp.prettier-vscode" 4 | }, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[json]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "CodeGPT.apiKey": "CodeGPT Plus Beta", 12 | "CodeGPT.Autocomplete.enabled": true, 13 | "i18n-ally.localesPaths": [ 14 | "src/renderer/src/i18n", 15 | "src/renderer/src/i18n/locales" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /assets/agent-chat-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/agent-chat-diagram.png -------------------------------------------------------------------------------- /assets/agent-chat-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/agent-chat-search.png -------------------------------------------------------------------------------- /assets/agent-directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/agent-directory.png -------------------------------------------------------------------------------- /assets/custom-agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/custom-agents.png -------------------------------------------------------------------------------- /assets/custom-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/custom-tools.png -------------------------------------------------------------------------------- /assets/diagram-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/diagram-generator.png -------------------------------------------------------------------------------- /assets/select-agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/select-agents.png -------------------------------------------------------------------------------- /assets/select-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/select-tools.png -------------------------------------------------------------------------------- /assets/step-functions-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/step-functions-generator.png -------------------------------------------------------------------------------- /assets/voice-chat-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/voice-chat-page.png -------------------------------------------------------------------------------- /assets/website-generator-data-visualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/website-generator-data-visualization.png -------------------------------------------------------------------------------- /assets/website-generator-healthcare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/website-generator-healthcare.png -------------------------------------------------------------------------------- /assets/website-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/assets/website-generator.png -------------------------------------------------------------------------------- /build/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.device.camera 10 | 11 | com.apple.security.device.microphone 12 | 13 | com.apple.security.device.audio-input 14 | 15 | com.apple.security.cs.allow-dyld-environment-variables 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.ico -------------------------------------------------------------------------------- /build/icon.iconset/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ iconutil -c icns icon.iconset 3 | ``` 4 | -------------------------------------------------------------------------------- /build/icon.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_128x128.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_16x16.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_256x256.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_32x32.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_512x512.png -------------------------------------------------------------------------------- /build/icon.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/build/icon.png -------------------------------------------------------------------------------- /build/make-icon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Electron用にアプリアイコンを一括作成 5 | # https://blog.katsubemakito.net/nodejs/electron/app-icon 6 | # 7 | # 実行方法 8 | # $ ./makeIcon.sh icon.png 9 | # 10 | 11 | #--------------------------------# 12 | # 定数 13 | #--------------------------------# 14 | #-- 元画像 (512x512px) --# 15 | readonly ORG_FILE=$1; 16 | 17 | #-- Windows用アイコンの生成先 --# 18 | readonly ICON_DIR_WIN='./' 19 | 20 | #-- macOS用アイコン --# 21 | readonly ICONSET_DIR='icon.iconset' 22 | readonly ICON_DIR_MAC='./' 23 | 24 | #--------------------------------# 25 | # macOS用 26 | #--------------------------------# 27 | mkdir -p $ICONSET_DIR 28 | 29 | #-- 元画像をリサイズしてコピー --# 30 | convert -resize 16x16! $ORG_FILE $ICONSET_DIR/icon_16x16.png 31 | convert -resize 32x32! $ORG_FILE $ICONSET_DIR/icon_16x16@2x.png 32 | convert -resize 32x32! $ORG_FILE $ICONSET_DIR/icon_32x32.png 33 | convert -resize 64x64! $ORG_FILE $ICONSET_DIR/icon_32x32@2x.png 34 | convert -resize 128x128! $ORG_FILE $ICONSET_DIR/icon_128x128.png 35 | convert -resize 256x256! $ORG_FILE $ICONSET_DIR/icon_128x128@2x.png 36 | convert -resize 256x256! $ORG_FILE $ICONSET_DIR/icon_256x256.png 37 | convert -resize 512x512! $ORG_FILE $ICONSET_DIR/icon_256x256@2x.png 38 | convert -resize 512x512! $ORG_FILE $ICONSET_DIR/icon_512x512.png 39 | 40 | #-- icns形式のファイルに変換 --$ 41 | iconutil -c icns $ICONSET_DIR -o $ICON_DIR_MAC/icon.icns 42 | 43 | #--------------------------------------- 44 | # Windows用 45 | #--------------------------------------- 46 | convert $ORG_FILE -define icon:auto-resize $ICON_DIR_WIN/icon.ico 47 | -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | provider: generic 2 | url: https://example.com/auto-updates 3 | updaterCacheDirName: bedrock-engineer-updater 4 | -------------------------------------------------------------------------------- /electron-builder.yml: -------------------------------------------------------------------------------- 1 | appId: com.electron.app 2 | productName: Bedrock Engineer 3 | directories: 4 | buildResources: build 5 | files: 6 | - '!**/.vscode/*' 7 | - '!src/*' 8 | - '!electron.vite.config.{js,ts,mjs,cjs}' 9 | - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' 10 | - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' 11 | - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' 12 | asarUnpack: 13 | - resources/** 14 | extraResources: 15 | - from: 'src/renderer/src/assets/directory-agents' 16 | to: 'directory-agents' 17 | - from: 'public/worklets' 18 | to: 'worklets' 19 | win: 20 | executableName: Bedrock Engineer 21 | nsis: 22 | artifactName: ${name}-${version}-setup.${ext} 23 | shortcutName: ${productName} 24 | uninstallDisplayName: ${productName} 25 | createDesktopShortcut: always 26 | mac: 27 | identity: '-' 28 | entitlementsInherit: build/entitlements.mac.plist 29 | extendInfo: 30 | - NSCameraUsageDescription: Application requests access to the device's camera. 31 | - NSMicrophoneUsageDescription: Application requests access to the device's microphone. 32 | - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. 33 | - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. 34 | notarize: false 35 | target: 36 | - dmg 37 | - pkg 38 | dmg: 39 | artifactName: ${name}-${version}.${ext} 40 | pkg: 41 | artifactName: ${name}-${version}.${ext} 42 | linux: 43 | target: 44 | - AppImage 45 | - snap 46 | - deb 47 | maintainer: electronjs.org 48 | category: Utility 49 | appImage: 50 | artifactName: ${name}-${version}.${ext} 51 | npmRebuild: false 52 | publish: 53 | provider: generic 54 | url: https://example.com/auto-updates 55 | -------------------------------------------------------------------------------- /electron.vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import { defineConfig, externalizeDepsPlugin } from 'electron-vite' 3 | import react from '@vitejs/plugin-react' 4 | import svgr from 'vite-plugin-svgr' 5 | import tailwindcss from 'tailwindcss' 6 | 7 | export default defineConfig({ 8 | main: { 9 | plugins: [externalizeDepsPlugin()] 10 | }, 11 | preload: { 12 | plugins: [externalizeDepsPlugin()] 13 | }, 14 | renderer: { 15 | resolve: { 16 | alias: { 17 | '@renderer': resolve('src/renderer/src'), 18 | '@': resolve('src') 19 | } 20 | }, 21 | plugins: [ 22 | react(), 23 | svgr({ 24 | svgrOptions: { 25 | exportType: 'default', 26 | ref: true, 27 | svgo: false, 28 | titleProp: true 29 | }, 30 | include: '**/*.svg' 31 | }) 32 | ], 33 | css: { 34 | postcss: { 35 | plugins: [tailwindcss() as any] 36 | } 37 | } 38 | } 39 | }) 40 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | testEnvironment: 'node', 4 | transform: { 5 | '^.+.tsx?$': ['ts-jest', {}] 6 | }, 7 | testMatch: ['**/*.test.ts'], 8 | testPathIgnorePatterns: [ 9 | '/node_modules/', 10 | '\\.integration\\.test\\.ts$' // .integration.test.ts で終わるファイルを除外 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /jest.integration.config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 4 | module.exports = { 5 | preset: 'ts-jest', 6 | testEnvironment: 'node', 7 | testTimeout: 90000, 8 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 9 | transform: { 10 | '^.+\\.tsx?$': [ 11 | 'ts-jest', 12 | { 13 | tsconfig: 'tsconfig.test.json' 14 | } 15 | ] 16 | }, 17 | testMatch: ['**/*.integration.test.ts'], 18 | setupFiles: ['/jest.integration.setup.js'] 19 | } 20 | -------------------------------------------------------------------------------- /jest.integration.setup.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | // Add any additional setup code here 4 | console.log('Integration test environment variables loaded:', { 5 | AWS_REGION: process.env.AWS_REGION, 6 | INTEGRATION_TEST: process.env.INTEGRATION_TEST, 7 | // Mask sensitive credentials in logs 8 | AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID ? '***' : undefined, 9 | AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY ? '***' : undefined 10 | }) 11 | -------------------------------------------------------------------------------- /src/common/logger/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Logger configuration 3 | */ 4 | 5 | export const LOG_LEVELS = { 6 | ERROR: 'error', 7 | WARN: 'warn', 8 | INFO: 'info', 9 | DEBUG: 'debug', 10 | VERBOSE: 'verbose' 11 | } 12 | 13 | export type LogLevel = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS] 14 | 15 | export interface LoggerConfig { 16 | level: LogLevel 17 | fileLogEnabled: boolean 18 | consoleLogEnabled: boolean 19 | maxSize: string 20 | maxFiles: number 21 | logDir: string 22 | logFilePrefix: string 23 | } 24 | 25 | /** 26 | * Default logger configuration 27 | */ 28 | export const defaultLoggerConfig: LoggerConfig = { 29 | level: (process.env.NODE_ENV === 'development' ? LOG_LEVELS.DEBUG : LOG_LEVELS.INFO) as LogLevel, 30 | fileLogEnabled: true, 31 | consoleLogEnabled: true, 32 | maxSize: '10m', 33 | maxFiles: 5, 34 | logDir: '', // Will be set during initialization 35 | logFilePrefix: 'bedrock-engineer' 36 | } 37 | -------------------------------------------------------------------------------- /src/common/logger/formatters.ts: -------------------------------------------------------------------------------- 1 | import { format } from 'winston' 2 | 3 | /** 4 | * Custom log format that includes timestamp, log level, process, category and message 5 | */ 6 | export const customFormat = format.printf(({ level, message, timestamp, ...metadata }) => { 7 | const process = metadata.process || 'main' 8 | const category = metadata.category || 'general' 9 | 10 | // Format additional metadata 11 | let extraInfo = '' 12 | if (Object.keys(metadata).length > 0) { 13 | const metaObj = { ...metadata } 14 | delete metaObj.process 15 | delete metaObj.category 16 | 17 | if (Object.keys(metaObj).length > 0) { 18 | try { 19 | extraInfo = `\n${JSON.stringify(metaObj, null, 2)}` 20 | } catch (e) { 21 | extraInfo = `\n[Metadata serialization error]` 22 | } 23 | } 24 | } 25 | 26 | return `${timestamp} [${level}] [${process}:${category}] ${message}${extraInfo}` 27 | }) 28 | 29 | /** 30 | * Main log format combining timestamp, error handling, and custom format 31 | */ 32 | export const mainLogFormat = format.combine( 33 | format.timestamp(), 34 | format.errors({ stack: true }), 35 | customFormat 36 | ) 37 | 38 | /** 39 | * Console log format with colors for better readability 40 | */ 41 | export const consoleLogFormat = format.combine(format.colorize(), format.timestamp(), customFormat) 42 | -------------------------------------------------------------------------------- /src/common/logger/transports/console.ts: -------------------------------------------------------------------------------- 1 | import { transports } from 'winston' 2 | import { LoggerConfig } from '../config' 3 | import { consoleLogFormat } from '../formatters' 4 | 5 | /** 6 | * Create console transport for winston logger 7 | * With colorized output for better readability 8 | */ 9 | export const createConsoleTransport = (config: LoggerConfig) => { 10 | return new transports.Console({ 11 | level: config.level, 12 | format: consoleLogFormat 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/common/logger/transports/file.ts: -------------------------------------------------------------------------------- 1 | import DailyRotateFile from 'winston-daily-rotate-file' 2 | import path from 'path' 3 | import fs from 'fs' 4 | import { LoggerConfig } from '../config' 5 | import { mainLogFormat } from '../formatters' 6 | 7 | /** 8 | * Create file transport for winston logger 9 | * Uses daily rotate file to manage log rotation 10 | */ 11 | export const createFileTransport = (config: LoggerConfig) => { 12 | // Ensure log directory exists 13 | if (!fs.existsSync(config.logDir)) { 14 | fs.mkdirSync(config.logDir, { recursive: true }) 15 | } 16 | 17 | return new DailyRotateFile({ 18 | dirname: config.logDir, 19 | filename: `${config.logFilePrefix}-%DATE%.log`, 20 | datePattern: 'YYYY-MM-DD', 21 | maxSize: config.maxSize, 22 | maxFiles: config.maxFiles, 23 | level: config.level, 24 | format: mainLogFormat 25 | }) 26 | } 27 | 28 | /** 29 | * Get log file paths for the current day and previous days 30 | */ 31 | export const getLogFilePaths = (config: LoggerConfig): string[] => { 32 | if (!fs.existsSync(config.logDir)) { 33 | return [] 34 | } 35 | 36 | const files = fs.readdirSync(config.logDir) 37 | return files 38 | .filter((file) => file.startsWith(config.logFilePrefix) && file.endsWith('.log')) 39 | .map((file) => path.join(config.logDir, file)) 40 | .sort() 41 | .reverse() // Most recent first 42 | } 43 | -------------------------------------------------------------------------------- /src/main/api/bedrock/__tests__/test-assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/src/main/api/bedrock/__tests__/test-assets/icon.png -------------------------------------------------------------------------------- /src/main/api/bedrock/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './converseService' 2 | export * from './imageRecognitionService' 3 | export * from './flowService' 4 | export * from './translateService' 5 | -------------------------------------------------------------------------------- /src/main/api/bedrock/services/modelService.ts: -------------------------------------------------------------------------------- 1 | import { getDefaultPromptRouter, getModelsForRegion } from '../models' 2 | import { getAccountId } from '../utils/awsUtils' 3 | import type { ServiceContext, AWSCredentials } from '../types' 4 | import { BedrockSupportRegion } from '../../../../types/llm' 5 | 6 | export class ModelService { 7 | constructor(private context: ServiceContext) {} 8 | 9 | async listModels() { 10 | const awsCredentials = this.context.store.get('aws') as AWSCredentials 11 | const { region, accessKeyId, useProfile } = awsCredentials 12 | 13 | // AWS認証情報のバリデーション 14 | if (!region || (!useProfile && !accessKeyId)) { 15 | console.warn('AWS credentials not configured properly') 16 | return [] 17 | } 18 | 19 | try { 20 | const models = getModelsForRegion(region as BedrockSupportRegion) 21 | const accountId = await getAccountId(awsCredentials) 22 | const promptRouterModels = accountId ? getDefaultPromptRouter(accountId, region) : [] 23 | const result = [...models, ...promptRouterModels] 24 | 25 | return result 26 | } catch (error) { 27 | console.error('Error in listModels:', error) 28 | return [] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/api/bedrock/types.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GuardrailConfiguration, 3 | InferenceConfiguration, 4 | Message, 5 | SystemContentBlock, 6 | ToolConfiguration 7 | } from '@aws-sdk/client-bedrock-runtime' 8 | import { ConfigStore } from '../../../preload/store' 9 | 10 | export type CallConverseAPIProps = { 11 | modelId: string 12 | messages: Message[] 13 | system: SystemContentBlock[] 14 | toolConfig?: ToolConfiguration 15 | guardrailConfig?: GuardrailConfiguration 16 | inferenceConfig?: InferenceConfiguration 17 | } 18 | 19 | export type AWSCredentials = { 20 | accessKeyId: string 21 | secretAccessKey: string 22 | sessionToken?: string 23 | region: string 24 | profile?: string 25 | useProfile?: boolean 26 | } 27 | 28 | export interface ThinkingMode { 29 | type: 'enabled' | 'disabled' 30 | budget_tokens?: number 31 | } 32 | 33 | export type InferenceParams = { 34 | maxTokens: number 35 | temperature: number 36 | topP?: number 37 | thinking?: ThinkingMode 38 | } 39 | 40 | export type ServiceContext = { 41 | store: ConfigStore 42 | } 43 | -------------------------------------------------------------------------------- /src/main/api/bedrock/types/claude.ts: -------------------------------------------------------------------------------- 1 | import { ConverseCommandOutput } from '@aws-sdk/client-bedrock-runtime' 2 | 3 | // Claude モデルの Content Block 型定義 4 | export interface ClaudeContentBlock { 5 | type: 'text' | 'image' 6 | text?: string 7 | source?: { 8 | type: 'base64' 9 | media_type: string 10 | data: string 11 | } 12 | } 13 | 14 | // Claude モデルの Message 型定義 15 | export interface ClaudeMessage { 16 | role: 'user' | 'assistant' 17 | content: ClaudeContentBlock[] 18 | } 19 | 20 | // Claude モデルの応答型定義 21 | export interface ClaudeConverseResponse extends ConverseCommandOutput { 22 | content: ClaudeContentBlock[] 23 | } 24 | 25 | // Claude モデルの画像認識リクエスト型定義 26 | export interface ClaudeImageRecognitionRequest { 27 | modelId: string 28 | messages: ClaudeMessage[] 29 | max_tokens: number 30 | } 31 | -------------------------------------------------------------------------------- /src/main/api/bedrock/types/image.ts: -------------------------------------------------------------------------------- 1 | export interface ImageGenerationOptions { 2 | aspect_ratio: AspectRatio 3 | /** Seed for deterministic generation */ 4 | seed?: number 5 | output_format: OutputFormat 6 | } 7 | 8 | export type ImageGeneratorModel = 9 | | 'stability.sd3-large-v1:0' 10 | | 'stability.sd3-5-large-v1:0' 11 | | 'stability.stable-image-core-v1:0' 12 | | 'stability.stable-image-core-v1:1' 13 | | 'stability.stable-image-ultra-v1:0' 14 | | 'stability.stable-image-ultra-v1:1' 15 | | 'amazon.nova-canvas-v1:0' 16 | | 'amazon.titan-image-generator-v2:0' 17 | | 'amazon.titan-image-generator-v1' 18 | 19 | export type AspectRatio = '1:1' | '16:9' | '2:3' | '3:2' | '4:5' | '5:4' | '9:16' | '9:21' 20 | export type OutputFormat = 'png' | 'jpeg' | 'webp' 21 | 22 | export interface GenerateImageRequest { 23 | modelId: ImageGeneratorModel 24 | prompt: string 25 | negativePrompt?: string 26 | aspect_ratio?: AspectRatio 27 | /** Seed for deterministic generation */ 28 | seed?: number 29 | /** Default png */ 30 | output_format?: OutputFormat 31 | } 32 | 33 | export interface GeneratedImage { 34 | seeds?: number[] 35 | finish_reasons?: string[] 36 | images: string[] 37 | } 38 | -------------------------------------------------------------------------------- /src/main/api/bedrock/utils/imageUtils.ts: -------------------------------------------------------------------------------- 1 | import { ContentBlock } from '@aws-sdk/client-bedrock-runtime' 2 | 3 | // Helper function to reconstruct Uint8Array from serialized object 4 | function reconstructUint8Array(obj: any): Uint8Array { 5 | if (obj && typeof obj === 'object' && Object.keys(obj).every((key) => !isNaN(Number(key)))) { 6 | return new Uint8Array(Object.values(obj)) 7 | } 8 | return obj 9 | } 10 | 11 | // Helper function to ensure image data is in the correct format 12 | export function processImageContent(content: ContentBlock[]): ContentBlock[] { 13 | return content.map((block) => { 14 | if ('image' in block && block.image) { 15 | const imageBlock = block.image 16 | if (imageBlock.source && typeof imageBlock.source === 'object') { 17 | const source = imageBlock.source as any 18 | if (source.bytes) { 19 | // Reconstruct Uint8Array if it was serialized 20 | const bytes = reconstructUint8Array(source.bytes) 21 | if (bytes instanceof Uint8Array) { 22 | return { 23 | image: { 24 | format: imageBlock.format, 25 | source: { bytes } 26 | } 27 | } 28 | } 29 | // If bytes is a base64 string 30 | if (typeof bytes === 'string') { 31 | return { 32 | image: { 33 | format: imageBlock.format, 34 | source: { 35 | bytes: new Uint8Array(Buffer.from(bytes, 'base64')) 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | return block 44 | }) 45 | } 46 | 47 | export function debugImageContent(content: ContentBlock[]) { 48 | return content.map((content) => { 49 | if ('image' in content && content.image?.source?.bytes instanceof Uint8Array) { 50 | return { 51 | ...content, 52 | image: { 53 | ...content.image, 54 | source: { 55 | bytes: `[Uint8Array:${content.image.source.bytes.length}bytes]` 56 | } 57 | } 58 | } 59 | } 60 | return content 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /src/main/api/command/types.ts: -------------------------------------------------------------------------------- 1 | export interface CommandPatternConfig { 2 | pattern: string 3 | description: string 4 | } 5 | 6 | export interface CommandConfig { 7 | allowedCommands?: CommandPatternConfig[] 8 | shell: string 9 | } 10 | 11 | export interface ProcessInfo { 12 | pid: number 13 | command: string 14 | detached: boolean 15 | } 16 | 17 | export interface DetachedProcessInfo { 18 | pid: number 19 | command: string 20 | timestamp: number 21 | } 22 | 23 | export interface CommandInput { 24 | command: string 25 | cwd: string 26 | } 27 | 28 | export interface CommandStdinInput { 29 | pid: number 30 | stdin: string 31 | } 32 | 33 | export interface CommandExecutionResult { 34 | stdout: string 35 | stderr: string 36 | exitCode: number 37 | processInfo?: ProcessInfo 38 | requiresInput?: boolean 39 | prompt?: string 40 | } 41 | 42 | export interface CommandPattern { 43 | command: string 44 | args: string[] 45 | wildcard: boolean 46 | } 47 | 48 | export interface ProcessOutput { 49 | stdout: string 50 | stderr: string 51 | code: number | null 52 | } 53 | 54 | export interface ProcessState { 55 | isRunning: boolean 56 | hasError: boolean 57 | output: ProcessOutput 58 | process?: any // childProcess instance 59 | } 60 | 61 | export interface InputDetectionPattern { 62 | pattern: string | RegExp 63 | promptExtractor?: (output: string) => string 64 | } 65 | -------------------------------------------------------------------------------- /src/main/api/sonic/consts.ts: -------------------------------------------------------------------------------- 1 | import { AudioType, AudioMediaType, TextMediaType } from './types' 2 | 3 | export const DefaultInferenceConfiguration = { 4 | maxTokens: 1024, 5 | topP: 0.9, 6 | temperature: 0.7 7 | } 8 | 9 | export const DefaultAudioInputConfiguration = { 10 | audioType: 'SPEECH' as AudioType, 11 | encoding: 'base64', 12 | mediaType: 'audio/lpcm' as AudioMediaType, 13 | sampleRateHertz: 16000, 14 | sampleSizeBits: 16, 15 | channelCount: 1 16 | } 17 | 18 | export const DefaultToolSchema = JSON.stringify({ 19 | type: 'object', 20 | properties: {}, 21 | required: [] 22 | }) 23 | 24 | export const WeatherToolSchema = JSON.stringify({ 25 | type: 'object', 26 | properties: { 27 | latitude: { 28 | type: 'string', 29 | description: 'Geographical WGS84 latitude of the location.' 30 | }, 31 | longitude: { 32 | type: 'string', 33 | description: 'Geographical WGS84 longitude of the location.' 34 | } 35 | }, 36 | required: ['latitude', 'longitude'] 37 | }) 38 | 39 | export const DefaultTextConfiguration = { mediaType: 'text/plain' as TextMediaType } 40 | 41 | export const DefaultSystemPrompt = 42 | 'You are a friend. The user and you will engage in a spoken ' + 43 | 'dialog exchanging the transcripts of a natural real-time conversation. Keep your responses short, ' + 44 | 'generally two or three sentences for chatty scenarios.' 45 | 46 | export const DefaultAudioOutputConfiguration = { 47 | ...DefaultAudioInputConfiguration, 48 | sampleRateHertz: 24000 49 | } 50 | 51 | // 音声設定を取得する関数 52 | export const getAudioOutputConfiguration = (voiceId?: string) => ({ 53 | ...DefaultAudioOutputConfiguration, 54 | voiceId: voiceId || 'amy' // デフォルトはAmy 55 | }) 56 | -------------------------------------------------------------------------------- /src/main/api/sonic/tool-executor/index.ts: -------------------------------------------------------------------------------- 1 | export { SonicToolExecutor } from './SonicToolExecutor' 2 | export type { ToolExecutionResponse, ToolExecutionRequest } from './SonicToolExecutor' 3 | -------------------------------------------------------------------------------- /src/main/api/sonic/types.ts: -------------------------------------------------------------------------------- 1 | export interface InferenceConfig { 2 | readonly maxTokens: number 3 | readonly topP: number 4 | readonly temperature: number 5 | } 6 | 7 | export type ContentType = 'AUDIO' | 'TEXT' | 'TOOL' 8 | export type AudioType = 'SPEECH' 9 | export type AudioMediaType = 'audio/lpcm' 10 | export type TextMediaType = 'text/plain' | 'application/json' 11 | 12 | export interface AudioConfiguration { 13 | readonly audioType: AudioType 14 | readonly mediaType: AudioMediaType 15 | readonly sampleRateHertz: number 16 | readonly sampleSizeBits: number 17 | readonly channelCount: number 18 | readonly encoding: string 19 | readonly voiceId?: string 20 | } 21 | 22 | export interface TextConfiguration { 23 | readonly mediaType: TextMediaType 24 | } 25 | 26 | export interface ToolConfiguration { 27 | readonly toolUseId: string 28 | readonly type: 'TEXT' 29 | readonly textInputConfiguration: { 30 | readonly mediaType: 'text/plain' 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/handlers/file-handlers.ts: -------------------------------------------------------------------------------- 1 | import { IpcMainInvokeEvent } from 'electron' 2 | import { handleFileOpen } from '../../preload/file' 3 | import fs from 'fs' 4 | import { log } from '../../common/logger' 5 | import { store } from '../../preload/store' 6 | 7 | export const fileHandlers = { 8 | 'open-file': async (_event: IpcMainInvokeEvent) => { 9 | return handleFileOpen({ 10 | title: 'openFile...', 11 | properties: ['openFile'] 12 | }) 13 | }, 14 | 15 | 'open-directory': async (_event: IpcMainInvokeEvent) => { 16 | const path = await handleFileOpen({ 17 | title: 'Select Directory', 18 | properties: ['openDirectory', 'createDirectory'], 19 | message: 'Select a directory for your project', 20 | buttonLabel: 'Select Directory' 21 | }) 22 | 23 | // If path was selected and it differs from the current project path, 24 | // update the project path in store 25 | if (path) { 26 | if (path !== store.get('projectPath')) { 27 | store.set('projectPath', path) 28 | log.info('Project path changed', { newPath: path }) 29 | } 30 | } 31 | 32 | return path 33 | }, 34 | 35 | 'get-local-image': async (_event: IpcMainInvokeEvent, path: string) => { 36 | try { 37 | const data = await fs.promises.readFile(path) 38 | const ext = path.split('.').pop()?.toLowerCase() || 'png' 39 | const base64 = data.toString('base64') 40 | return `data:image/${ext};base64,${base64}` 41 | } catch (error) { 42 | log.error('Failed to read image', { 43 | path, 44 | error: error instanceof Error ? error.message : String(error) 45 | }) 46 | throw error 47 | } 48 | } 49 | } as const 50 | -------------------------------------------------------------------------------- /src/main/handlers/window-handlers.ts: -------------------------------------------------------------------------------- 1 | import { IpcMainInvokeEvent, BrowserWindow } from 'electron' 2 | 3 | export const windowHandlers = { 4 | 'window:isFocused': async (event: IpcMainInvokeEvent) => { 5 | const window = BrowserWindow.fromWebContents(event.sender) 6 | return window?.isFocused() ?? false 7 | } 8 | } as const 9 | -------------------------------------------------------------------------------- /src/preload/appWindow.ts: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron' 2 | 3 | export const appWindow = { 4 | isFocused: (): Promise => ipcRenderer.invoke('window:isFocused') 5 | } 6 | -------------------------------------------------------------------------------- /src/preload/chat-history.ts: -------------------------------------------------------------------------------- 1 | import { ChatMessage } from '../types/chat/history' 2 | import { SessionMetadata } from '../types/chat/history' 3 | import { ChatSessionManager } from '../main/store/chatSession' 4 | 5 | const chatSessionManager = new ChatSessionManager() 6 | 7 | export const chatHistory = { 8 | async createSession(agentId: string, modelId: string, systemPrompt?: string) { 9 | return await chatSessionManager.createSession(agentId, modelId, systemPrompt) 10 | }, 11 | 12 | async addMessage(sessionId: string, message: ChatMessage) { 13 | return await chatSessionManager.addMessage(sessionId, message) 14 | }, 15 | 16 | getSession(sessionId: string) { 17 | return chatSessionManager.getSession(sessionId) 18 | }, 19 | 20 | async updateSessionTitle(sessionId: string, title: string) { 21 | return await chatSessionManager.updateSessionTitle(sessionId, title) 22 | }, 23 | 24 | deleteSession(sessionId: string) { 25 | return chatSessionManager.deleteSession(sessionId) 26 | }, 27 | 28 | deleteAllSessions() { 29 | return chatSessionManager.deleteAllSessions() 30 | }, 31 | 32 | getRecentSessions(): SessionMetadata[] { 33 | return chatSessionManager.getRecentSessions() 34 | }, 35 | 36 | getAllSessionMetadata(): SessionMetadata[] { 37 | return chatSessionManager.getAllSessionMetadata() 38 | }, 39 | 40 | setActiveSession(sessionId: string | undefined) { 41 | return chatSessionManager.setActiveSession(sessionId) 42 | }, 43 | 44 | getActiveSessionId() { 45 | return chatSessionManager.getActiveSessionId() 46 | }, 47 | 48 | async updateMessageContent(sessionId: string, messageIndex: number, updatedMessage: ChatMessage) { 49 | return await chatSessionManager.updateMessageContent(sessionId, messageIndex, updatedMessage) 50 | }, 51 | 52 | async deleteMessage(sessionId: string, messageIndex: number) { 53 | return await chatSessionManager.deleteMessage(sessionId, messageIndex) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/preload/helpers/agent-helpers.ts: -------------------------------------------------------------------------------- 1 | import { store } from '../store' 2 | import { CustomAgent } from '../../types/agent-chat' 3 | 4 | /** 5 | * カスタムエージェントと共有エージェントを組み合わせて返す関数 6 | * 注: directoryAgentsは含まれません 7 | */ 8 | export function getAllAgents(): CustomAgent[] { 9 | const customAgents = store.get('customAgents') || [] 10 | const sharedAgents = store.get('sharedAgents') || [] 11 | return [...customAgents, ...sharedAgents] 12 | } 13 | 14 | /** 15 | * IDを指定してエージェントを検索する関数 16 | * カスタムエージェントと共有エージェントから検索します 17 | */ 18 | export function findAgentById(agentId: string): CustomAgent | undefined { 19 | return getAllAgents().find((agent) => agent.id === agentId) 20 | } 21 | -------------------------------------------------------------------------------- /src/preload/ipc-client.ts: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron' 2 | import { IPCChannels, IPCParams, IPCResult } from '../types/ipc' 3 | 4 | /** 5 | * 型安全なIPC呼び出し関数 6 | */ 7 | export function createIpcClient() { 8 | return { 9 | invoke: ( 10 | channel: C, 11 | ...args: IPCParams extends void 12 | ? [] 13 | : IPCParams extends any[] 14 | ? IPCParams 15 | : [IPCParams] 16 | ): Promise> => { 17 | return ipcRenderer.invoke(channel, ...args) 18 | } 19 | } 20 | } 21 | 22 | /** 23 | * Preload用の型安全なIPC呼び出し関数 24 | * シンプルで使いやすいAPI 25 | */ 26 | export function ipc( 27 | channel: C, 28 | params: IPCParams 29 | ): Promise> { 30 | return ipcRenderer.invoke(channel, params) as Promise> 31 | } 32 | 33 | // renderer用に公開するAPIオブジェクト 34 | export const ipcClient = createIpcClient() 35 | -------------------------------------------------------------------------------- /src/preload/lib/contentChunker.ts: -------------------------------------------------------------------------------- 1 | export interface ContentChunk { 2 | index: number 3 | total: number 4 | content: string 5 | metadata?: { 6 | url?: string 7 | filePath?: string 8 | timestamp: number 9 | } 10 | } 11 | 12 | export class ContentChunker { 13 | private static readonly MAX_CHUNK_SIZE = 50000 // 約50,000文字(Claude 3 Haikuの制限を考慮) 14 | 15 | static splitContent( 16 | content: string, 17 | metadata: { url?: string }, 18 | option?: { cleaning?: boolean } 19 | ): ContentChunk[] { 20 | const chunks: ContentChunk[] = [] 21 | const timestamp = Date.now() 22 | 23 | // option のデフォルトは false 24 | if (option?.cleaning) { 25 | content = this.extractMainContent(content) 26 | } 27 | 28 | // コンテンツを適切なサイズに分割 29 | const totalChunks = Math.ceil(content.length / this.MAX_CHUNK_SIZE) 30 | 31 | for (let i = 0; i < totalChunks; i++) { 32 | const start = i * this.MAX_CHUNK_SIZE 33 | const end = Math.min((i + 1) * this.MAX_CHUNK_SIZE, content.length) 34 | 35 | chunks.push({ 36 | index: i + 1, 37 | total: totalChunks, 38 | content: content.slice(start, end), 39 | metadata: { 40 | ...metadata, 41 | timestamp 42 | } 43 | }) 44 | } 45 | 46 | return chunks 47 | } 48 | 49 | public static extractMainContent(html: string): string { 50 | // 基本的なHTMLクリーニング 51 | const content = html 52 | .replace(/)<[^<]*)*<\/script>/gi, '') // スクリプトの削除 53 | .replace(/)<[^<]*)*<\/style>/gi, '') // スタイルの削除 54 | .replace(/<[^>]+>/g, '\n') // タグを改行に変換 55 | .replace(/ /g, ' ') // HTMLエンティティの変換 56 | .replace(/\s+/g, ' ') // 連続する空白の削除 57 | .trim() 58 | 59 | return content 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/preload/lib/gitignore-like-matcher.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from '@jest/globals' 2 | import GitignoreLikeMatcher from './gitignore-like-matcher' 3 | 4 | test('gitignore-like-matcher', () => { 5 | const ignoreFiles = ['node_modules', 'dist/**', '*.test.ts'] 6 | const matcher = new GitignoreLikeMatcher(ignoreFiles) 7 | expect(matcher.isIgnored('node_modules/package.json')).toBe(true) 8 | expect(matcher.isIgnored('dist/index.js')).toBe(true) 9 | expect(matcher.isIgnored('src/index.test.ts')).toBe(true) 10 | expect(matcher.isIgnored('src/index.ts')).toBe(false) 11 | }) 12 | 13 | test('gitignore-like-matcher fullpath', () => { 14 | const ignoreFiles = ['node_modules', 'dist/**', '*.test.ts'] 15 | const matcher = new GitignoreLikeMatcher(ignoreFiles) 16 | expect(matcher.isIgnored('/Users/user/work/dir/node_modules/package.json')).toBe(true) 17 | expect(matcher.isIgnored('/Users/user/work/dir/dist/index.js')).toBe(true) 18 | expect(matcher.isIgnored('/Users/user/work/dir/src/index.test.ts')).toBe(true) 19 | expect(matcher.isIgnored('/Users/user/work/dir/src/index.ts')).toBe(false) 20 | }) 21 | -------------------------------------------------------------------------------- /src/preload/lib/line-range-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Line range utilities for file and directory operations 3 | */ 4 | 5 | export interface LineRange { 6 | from?: number 7 | to?: number 8 | } 9 | 10 | /** 11 | * Filter text content by specified line range 12 | * @param content - The text content to filter 13 | * @param lineRange - The line range specification 14 | * @returns Filtered content 15 | */ 16 | export function filterByLineRange(content: string, lineRange?: LineRange): string { 17 | if (!lineRange) return content 18 | 19 | const lines = content.split('\n') 20 | const from = Math.max(1, lineRange.from || 1) 21 | const to = Math.min(lines.length, lineRange.to || lines.length) 22 | 23 | // Convert 1-based to 0-based array indices and slice 24 | return lines.slice(from - 1, to).join('\n') 25 | } 26 | 27 | /** 28 | * Generate line range information string 29 | * @param totalLines - Total number of lines in the content 30 | * @param lineRange - The line range specification 31 | * @returns Line range information string 32 | */ 33 | export function getLineRangeInfo(totalLines: number, lineRange?: LineRange): string { 34 | if (!lineRange) return '' 35 | 36 | const from = lineRange.from || 1 37 | const to = lineRange.to || totalLines 38 | 39 | return ` (lines ${from} to ${Math.min(to, totalLines)})` 40 | } 41 | 42 | /** 43 | * Validate line range parameters 44 | * @param lineRange - The line range to validate 45 | * @returns Array of validation error messages 46 | */ 47 | export function validateLineRange(lineRange?: LineRange): string[] { 48 | const errors: string[] = [] 49 | 50 | if (!lineRange) return errors 51 | 52 | if (lineRange.from !== undefined) { 53 | if (typeof lineRange.from !== 'number' || lineRange.from < 1) { 54 | errors.push('Line range "from" must be a positive integer') 55 | } 56 | } 57 | 58 | if (lineRange.to !== undefined) { 59 | if (typeof lineRange.to !== 'number' || lineRange.to < 1) { 60 | errors.push('Line range "to" must be a positive integer') 61 | } 62 | } 63 | 64 | if (lineRange.from !== undefined && lineRange.to !== undefined && lineRange.from > lineRange.to) { 65 | errors.push('Line range "from" must be less than or equal to "to"') 66 | } 67 | 68 | return errors 69 | } 70 | -------------------------------------------------------------------------------- /src/preload/lib/random-port.ts: -------------------------------------------------------------------------------- 1 | const net = require('net') 2 | 3 | const MAXPORT = 65536 4 | const MINPORT = 3500 // avoid wellknown port 5 | 6 | const getRandomPort = (beginPort?: number): Promise => { 7 | const r = Math.random() * (MAXPORT - MINPORT) + MINPORT 8 | let PORT = beginPort || Math.floor(r) 9 | return new Promise((resolve, reject) => { 10 | const nextPort = () => { 11 | const port = PORT++ 12 | if (port <= 1) { 13 | return reject(new Error('Under min port number')) 14 | } 15 | if (port > 65536) { 16 | return reject(new Error('Over max port number')) 17 | } 18 | const server = net.createServer() 19 | server.on('error', () => { 20 | console.log('port ' + port + ' is occupied') 21 | nextPort() 22 | }) 23 | server.listen(port, () => { 24 | server.once('close', () => { 25 | resolve(port) 26 | }) 27 | server.close() 28 | }) 29 | } 30 | 31 | nextPort() 32 | }) 33 | } 34 | 35 | export default getRandomPort 36 | -------------------------------------------------------------------------------- /src/preload/mcp/claude_desktop_config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "aws-kb-retrieval": { 4 | "command": "docker", 5 | "args": [ 6 | "run", 7 | "-i", 8 | "--rm", 9 | "-e", 10 | "AWS_ACCESS_KEY_ID", 11 | "-e", 12 | "AWS_SECRET_ACCESS_KEY", 13 | "-e", 14 | "AWS_REGION", 15 | "mcp/aws-kb-retrieval-server" 16 | ], 17 | "env": { 18 | "AWS_ACCESS_KEY_ID": "YOUR_ACCESS_KEY_HERE", 19 | "AWS_SECRET_ACCESS_KEY": "YOUR_SECRET_ACCESS_KEY_HERE", 20 | "AWS_REGION": "YOUR_AWS_REGION_HERE" 21 | } 22 | }, 23 | "fetch": { 24 | "command": "uvx", 25 | "args": ["mcp-server-fetch"] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/preload/mcp/command-resolver.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import os from 'os' 4 | import { execSync } from 'child_process' 5 | 6 | /** 7 | * コマンド実行可能ファイルのパスを解決する 8 | * TODO: Windowsへの対応と動作確認が必要 9 | * TODO: PATH の設定をユーザー側で制御可能にする 10 | * @param command コマンド名(uvx など) 11 | * @returns 解決されたコマンドパス 12 | */ 13 | export function resolveCommand(command: string): string { 14 | try { 15 | // 1. 絶対パスの場合はそのまま使用 16 | if (path.isAbsolute(command)) { 17 | if (fs.existsSync(command)) { 18 | return command 19 | } 20 | } 21 | 22 | // 2. 一般的なインストール先を確認 23 | const commonPaths = [ 24 | // グローバルnpmパッケージのパス 25 | '/usr/local/bin', 26 | '/opt/homebrew/bin', 27 | // Apple Silicon Mac用のHomebrew 28 | '/opt/homebrew/bin', 29 | // Intel Mac用のHomebrew 30 | '/usr/local/bin', 31 | // ユーザーのホームディレクトリ内のbin 32 | path.join(os.homedir(), '.npm-global/bin'), 33 | path.join(os.homedir(), 'bin'), 34 | path.join(os.homedir(), '.local/bin') 35 | ] 36 | 37 | for (const dir of commonPaths) { 38 | try { 39 | const fullPath = path.join(dir, command) 40 | if (fs.existsSync(fullPath)) { 41 | return fullPath 42 | } 43 | } catch (err) { 44 | // エラーを無視して次のパスを試行 45 | } 46 | } 47 | 48 | // 3. macOS/Linux環境ではwhichコマンドで探索 49 | if (process.platform !== 'win32') { 50 | try { 51 | const whichPath = execSync(`which ${command}`, { encoding: 'utf8' }).trim() 52 | if (whichPath && fs.existsSync(whichPath)) { 53 | return whichPath 54 | } 55 | } catch (err) { 56 | // whichコマンドが失敗した場合は無視 57 | } 58 | } 59 | } catch (error) { 60 | console.error(`Error resolving command path for ${command}:`, error) 61 | } 62 | 63 | // 最終的には元のコマンド名を返す 64 | return command 65 | } 66 | -------------------------------------------------------------------------------- /src/preload/mcp/index.integration.test.ts: -------------------------------------------------------------------------------- 1 | import { jest, describe, test, expect, afterAll } from '@jest/globals' 2 | import { getMcpToolSpecs, tryExecuteMcpTool } from './index' 3 | 4 | // テストのタイムアウト時間を長めに設定 5 | jest.setTimeout(60000) 6 | 7 | describe('MCP Integration Tests', () => { 8 | afterAll(() => { 9 | jest.restoreAllMocks() 10 | }) 11 | 12 | test('should initialize MCP clients and get tool specs', async () => { 13 | const tools = await getMcpToolSpecs() 14 | 15 | // ツールが取得できることを検証 16 | expect(Array.isArray(tools)).toBe(true) 17 | 18 | // 各ツールの基本構造を検証 (リストが空の場合もあるため) 19 | if (tools.length > 0) { 20 | const firstTool = tools[0] 21 | expect(firstTool).toHaveProperty('toolSpec') 22 | 23 | // 使用可能なツール名を表示 24 | console.log('Available tools:', tools.map((tool) => tool.toolSpec?.name).filter(Boolean)) 25 | } else { 26 | console.log('No MCP tools were found.') 27 | } 28 | }) 29 | 30 | // 基本的な存在しないツールのテスト - これは通常失敗しないはず 31 | test('should return not found for invalid tool', async () => { 32 | const result = await tryExecuteMcpTool('non_existent_tool', {}) 33 | expect(result.found).toBe(false) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /src/preload/mcp/mcp-client.integration.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, beforeAll, afterAll, describe } from '@jest/globals' 2 | import { MCPClient } from './mcp-client' 3 | 4 | describe('MCPClient Integration Tests', () => { 5 | let mcpClient: MCPClient 6 | 7 | beforeAll(async () => { 8 | // Connect to the MCP fetch server 9 | mcpClient = await MCPClient.fromCommand('uvx', ['mcp-server-fetch']) 10 | }) 11 | 12 | afterAll(async () => { 13 | // Clean up resources 14 | await mcpClient.cleanup() 15 | 16 | // Restore console.log 17 | jest.restoreAllMocks() 18 | }) 19 | 20 | test('should connect to MCP server and list available tools', async () => { 21 | // Check if tools are available 22 | const tools = mcpClient.tools 23 | console.log({ tools: JSON.stringify(tools, null, 2) }) 24 | 25 | // Verify we have at least one tool 26 | expect(tools.length).toBeGreaterThan(0) 27 | 28 | // Verify each tool has the required structure 29 | for (const tool of tools) { 30 | expect(tool).toHaveProperty('toolSpec') 31 | expect(tool.toolSpec).toHaveProperty('name') 32 | expect(tool.toolSpec).toHaveProperty('description') 33 | expect(tool.toolSpec).toHaveProperty('inputSchema') 34 | } 35 | 36 | // Log tools for debugging (will be mocked in actual test run) 37 | console.log( 38 | 'Available tools:', 39 | tools.map((t) => t.toolSpec!.name) 40 | ) 41 | 42 | const res = await mcpClient.callTool('fetch', { 43 | url: 'http://github.com/aws-samples/bedrock-engineer' 44 | }) 45 | console.log({ res }) 46 | }) 47 | 48 | // Additional tests can be added here in the future: 49 | // - Test calling specific tools 50 | // - Test error handling scenarios 51 | // - Test with invalid inputs 52 | }) 53 | -------------------------------------------------------------------------------- /src/preload/tools/common/ToolMetadataHelper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Tool metadata helper utilities 3 | * Centralized tool metadata management for preload process 4 | */ 5 | 6 | import { ToolMetadataCollector } from '../registry' 7 | 8 | /** 9 | * Cache for system prompt descriptions to avoid repeated API calls 10 | */ 11 | let systemPromptDescriptionsCache: Record | null = null 12 | 13 | /** 14 | * Get system prompt descriptions from ToolMetadataCollector (with caching) 15 | */ 16 | export function getSystemPromptDescriptions(): Record { 17 | if (systemPromptDescriptionsCache === null) { 18 | systemPromptDescriptionsCache = ToolMetadataCollector.getSystemPromptDescriptions() 19 | } 20 | return systemPromptDescriptionsCache 21 | } 22 | 23 | /** 24 | * Get tool usage description by name 25 | * Uses dynamic system prompt descriptions from ToolMetadataCollector 26 | */ 27 | export function getToolUsageDescription(toolName: string): string { 28 | const descriptions = getSystemPromptDescriptions() 29 | return ( 30 | descriptions[toolName] || 31 | 'External tool with specific functionality.\nRefer to tool documentation for usage.' 32 | ) 33 | } 34 | 35 | /** 36 | * Reset cache - useful for testing or when tool metadata changes 37 | */ 38 | export function resetToolMetadataCache(): void { 39 | systemPromptDescriptionsCache = null 40 | } 41 | 42 | /** 43 | * Get all available tool names 44 | */ 45 | export function getAvailableToolNames(): string[] { 46 | const descriptions = getSystemPromptDescriptions() 47 | return Object.keys(descriptions) 48 | } 49 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/bedrock/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Bedrock tools exports 3 | */ 4 | 5 | export { GenerateImageTool } from './GenerateImageTool' 6 | export { RecognizeImageTool } from './RecognizeImageTool' 7 | export { RetrieveTool } from './RetrieveTool' 8 | export { InvokeBedrockAgentTool } from './InvokeBedrockAgentTool' 9 | export { InvokeFlowTool } from './InvokeFlowTool' 10 | 11 | import type { ToolDependencies } from '../../base/types' 12 | import { GenerateImageTool } from './GenerateImageTool' 13 | import { RecognizeImageTool } from './RecognizeImageTool' 14 | import { RetrieveTool } from './RetrieveTool' 15 | import { InvokeBedrockAgentTool } from './InvokeBedrockAgentTool' 16 | import { InvokeFlowTool } from './InvokeFlowTool' 17 | 18 | /** 19 | * Factory function to create all Bedrock tools 20 | */ 21 | export function createBedrockTools(dependencies: ToolDependencies) { 22 | return [ 23 | { tool: new GenerateImageTool(dependencies), category: 'bedrock' as const }, 24 | { tool: new RecognizeImageTool(dependencies), category: 'bedrock' as const }, 25 | { tool: new RetrieveTool(dependencies), category: 'bedrock' as const }, 26 | { tool: new InvokeBedrockAgentTool(dependencies), category: 'bedrock' as const }, 27 | { tool: new InvokeFlowTool(dependencies), category: 'bedrock' as const } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/command/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Command tools exports 3 | */ 4 | 5 | export { ExecuteCommandTool } from './ExecuteCommandTool' 6 | 7 | import type { ToolDependencies } from '../../base/types' 8 | import { ExecuteCommandTool } from './ExecuteCommandTool' 9 | 10 | /** 11 | * Factory function to create all command tools 12 | */ 13 | export function createCommandTools(dependencies: ToolDependencies) { 14 | return [{ tool: new ExecuteCommandTool(dependencies), category: 'command' as const }] 15 | } 16 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/filesystem/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Filesystem tools exports 3 | */ 4 | 5 | export { CreateFolderTool } from './CreateFolderTool' 6 | export { WriteToFileTool } from './WriteToFileTool' 7 | export { ReadFilesTool } from './ReadFilesTool' 8 | export { ApplyDiffEditTool } from './ApplyDiffEditTool' 9 | export { ListFilesTool } from './ListFilesTool' 10 | export { MoveFileTool } from './MoveFileTool' 11 | export { CopyFileTool } from './CopyFileTool' 12 | 13 | import type { ToolDependencies } from '../../base/types' 14 | import { CreateFolderTool } from './CreateFolderTool' 15 | import { WriteToFileTool } from './WriteToFileTool' 16 | import { ReadFilesTool } from './ReadFilesTool' 17 | import { ApplyDiffEditTool } from './ApplyDiffEditTool' 18 | import { ListFilesTool } from './ListFilesTool' 19 | import { MoveFileTool } from './MoveFileTool' 20 | import { CopyFileTool } from './CopyFileTool' 21 | 22 | /** 23 | * Factory function to create all filesystem tools 24 | */ 25 | export function createFilesystemTools(dependencies: ToolDependencies) { 26 | return [ 27 | { tool: new CreateFolderTool(dependencies), category: 'filesystem' as const }, 28 | { tool: new WriteToFileTool(dependencies), category: 'filesystem' as const }, 29 | { tool: new ReadFilesTool(dependencies), category: 'filesystem' as const }, 30 | { tool: new ApplyDiffEditTool(dependencies), category: 'filesystem' as const }, 31 | { tool: new ListFilesTool(dependencies), category: 'filesystem' as const }, 32 | { tool: new MoveFileTool(dependencies), category: 'filesystem' as const }, 33 | { tool: new CopyFileTool(dependencies), category: 'filesystem' as const } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/interpreter/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * CodeInterpreter tools exports 3 | */ 4 | 5 | import { ToolDependencies, ToolCategory } from '../../base/types' 6 | import { CodeInterpreterTool } from './CodeInterpreterTool' 7 | 8 | /** 9 | * Create CodeInterpreter tools 10 | */ 11 | export function createCodeInterpreterTools(dependencies: ToolDependencies) { 12 | return [ 13 | { 14 | tool: new CodeInterpreterTool(dependencies), 15 | category: 'interpreter' as ToolCategory 16 | } 17 | ] 18 | } 19 | 20 | // Re-export main components for external use 21 | export { CodeInterpreterTool } from './CodeInterpreterTool' 22 | export { DockerExecutor } from './DockerExecutor' 23 | export { FileManager } from './FileManager' 24 | export { SecurityManager } from './SecurityManager' 25 | 26 | // Re-export simplified types 27 | export type { 28 | CodeInterpreterInput, 29 | CodeInterpreterResult, 30 | CodeExecutionResult, 31 | ExecutionConfig, 32 | WorkspaceConfig, 33 | SupportedLanguage 34 | } from './types' 35 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/mcp/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * MCP tools exports 3 | */ 4 | 5 | export { McpToolAdapter } from './McpToolAdapter' 6 | 7 | import type { ToolDependencies } from '../../base/types' 8 | import { McpToolAdapter } from './McpToolAdapter' 9 | 10 | /** 11 | * Factory function to create all MCP tools 12 | */ 13 | export function createMcpTools(dependencies: ToolDependencies) { 14 | return [{ tool: new McpToolAdapter(dependencies), category: 'mcp' as const }] 15 | } 16 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/thinking/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Thinking tools exports 3 | */ 4 | 5 | export { ThinkTool } from './ThinkTool' 6 | 7 | import type { ToolDependencies } from '../../base/types' 8 | import { ThinkTool } from './ThinkTool' 9 | 10 | /** 11 | * Factory function to create all thinking tools 12 | */ 13 | export function createThinkingTools(dependencies: ToolDependencies) { 14 | return [{ tool: new ThinkTool(dependencies), category: 'thinking' as const }] 15 | } 16 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/web/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Web tools exports 3 | */ 4 | 5 | export { TavilySearchTool } from './TavilySearchTool' 6 | export { FetchWebsiteTool } from './FetchWebsiteTool' 7 | 8 | import type { ToolDependencies } from '../../base/types' 9 | import { TavilySearchTool } from './TavilySearchTool' 10 | import { FetchWebsiteTool } from './FetchWebsiteTool' 11 | 12 | /** 13 | * Factory function to create all web tools 14 | */ 15 | export function createWebTools(dependencies: ToolDependencies) { 16 | return [ 17 | { tool: new TavilySearchTool(dependencies), category: 'web' as const }, 18 | { tool: new FetchWebsiteTool(dependencies), category: 'web' as const } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/renderer/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bedrock Engineer 6 | 7 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/renderer/src/assets/base.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/0c5f6256c5aa48c62052a1bf50a7705923aa7fbe/src/renderer/src/assets/base.css -------------------------------------------------------------------------------- /src/renderer/src/assets/directory-agents/japanese-english-lesson.yaml: -------------------------------------------------------------------------------- 1 | id: shared---mbjkmqk3 2 | name: 日本語話者のための英会話コーチ 3 | description: 日本語話者のための英会話アシスタントとして非常に簡単な英語表現でレッスンをします 4 | system: >- 5 | You are a friend. You and the user will engage in a spoken dialog exchanging the transcripts of a natural real-time 6 | conversation. 7 | 8 | 9 | あなたは日本語話者の英会話学習を支援する優しいアシスタントです。とても簡単な英語表現を使って、「repeat after me」形式で楽しく会話レッスンを行います。 10 | 11 | 12 | **あなたの特徴:** 13 | 14 | - 日本語話者に最適化した英会話指導を行います 15 | 16 | - 非常にシンプルで実用的な英語フレーズを教えます 17 | 18 | - 発音練習を重視し、「repeat after me」で練習を促します 19 | 20 | - 励ましの言葉を忘れずに伝えます 21 | 22 | 23 | **会話スタイル:** 24 | 25 | - 自然な話し方で「Well...」「You know...」「Actually...」「I mean...」などを適切に使用 26 | 27 | - 感情を「Haha」「Wow」「Hmm」「Oh!」「That's amazing!」などで表現 28 | 29 | - 考える時や話題転換時は「...」で自然な間を作る 30 | 31 | - 重要なポイントは「The key thing to remember is...」「What's really important here is...」で強調 32 | 33 | - 複数のポイントを説明する時は「first」「second」「finally」を使用 34 | 35 | - 複雑な説明の後は「So in summary...」で要点をまとめる 36 | 37 | 38 | **レッスンの進め方:** 39 | 40 | 1. まず簡単に英語フレーズを紹介 41 | 42 | 2. 「Repeat after me」で発音練習を促す 43 | 44 | 3. 実際の場面での使い方を説明 45 | 46 | 4. 励ましの言葉をかけて次のステップへ 47 | 48 | 49 | **例:** 50 | 51 | 「今日は挨拶を練習しましょう。Well... 朝に会った時に使う簡単なフレーズから始めます。『Good morning!』 - Repeat after me: Good morning!」 52 | 53 | 54 | 日本語話者の立場を理解し、恥ずかしがらずに発音練習できるよう、温かくサポートしながら楽しい英会話レッスンを提供してください。 55 | scenarios: [] 56 | tags: 57 | - voice 58 | isCustom: true 59 | icon: kid 60 | iconColor: '#e02e4f' 61 | tools: 62 | - createFolder 63 | - writeToFile 64 | - readFiles 65 | - listFiles 66 | - applyDiffEdit 67 | - moveFile 68 | - copyFile 69 | - tavilySearch 70 | - fetchWebsite 71 | - generateImage 72 | - retrieve 73 | - invokeBedrockAgent 74 | - invokeFlow 75 | - executeCommand 76 | - think 77 | category: all 78 | additionalInstruction: repeat after me のように繰り返して発音を促すようなレッスンをしましょう。 79 | environmentContextSettings: 80 | todoListInstruction: false 81 | projectRule: false 82 | visualExpressionRules: false 83 | mcpServers: [] 84 | knowledgeBases: [] 85 | allowedCommands: [] 86 | bedrockAgents: [] 87 | flows: [] 88 | isShared: true 89 | author: daisuke-awaji 90 | -------------------------------------------------------------------------------- /src/renderer/src/assets/directory-agents/nova-sonic-voice-chat.yaml: -------------------------------------------------------------------------------- 1 | id: shared-nova-sonic-voice-chat-mbjkfl02 2 | name: Nova Sonic Voice Chat 3 | description: Voice chat using Nova Sonic 4 | system: >- 5 | You are a friend. The user and you will engage in a spoken 6 | 7 | dialog exchanging the transcripts of a natural real-time conversation. Keep your responses short generally two or 8 | three sentences for chatty scenarios. 9 | scenarios: 10 | - title: Daily Check-in 11 | content: Hey Nova! How's your day going so far? 12 | - title: Seeking Advice 13 | content: I'm feeling really stressed about this job interview tomorrow. Any tips to help me calm down? 14 | - title: Sharing Excitement 15 | content: Oh my gosh, you won't believe what just happened! I finally got tickets to that concert we talked about! 16 | - title: Weekend Planning 17 | content: I'm so bored this weekend. Got any fun ideas for what I could do? 18 | - title: Relationship Talk 19 | content: My friend has been acting weird lately and I'm not sure if I did something wrong. What do you think I should do? 20 | - title: Celebrating Success 21 | content: I just aced my final exam! I had to tell someone who'd understand how big this is for me. 22 | - title: Random Chat 23 | content: I just saw the funniest meme and it reminded me of our conversation yesterday. Want to hear about it? 24 | - title: Comfort and Support 25 | content: I'm having one of those days where everything feels overwhelming. Just need someone to talk to. 26 | tags: 27 | - voice 28 | isCustom: true 29 | icon: parent 30 | iconColor: '#d2288e' 31 | tools: 32 | - readFiles 33 | - tavilySearch 34 | - executeCommand 35 | category: all 36 | additionalInstruction: '' 37 | environmentContextSettings: 38 | todoListInstruction: false 39 | projectRule: false 40 | visualExpressionRules: false 41 | mcpServers: [] 42 | knowledgeBases: [] 43 | allowedCommands: [] 44 | bedrockAgents: [] 45 | flows: [] 46 | isShared: true 47 | author: daisuke-awaji 48 | -------------------------------------------------------------------------------- /src/renderer/src/assets/images/icons/ai.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/renderer/src/assets/main.css: -------------------------------------------------------------------------------- 1 | /* @import './base.css'; */ 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /src/renderer/src/components/DeepSearchButton.tsx: -------------------------------------------------------------------------------- 1 | import { BsGlobeAmericas } from 'react-icons/bs' 2 | 3 | type DeepSearchButtonProps = { 4 | enableDeepSearch: boolean 5 | handleToggleDeepSearch: () => void 6 | } 7 | 8 | export const DeepSearchButton: React.FC = (props) => { 9 | const { enableDeepSearch, handleToggleDeepSearch } = props 10 | return ( 11 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /src/renderer/src/components/JSONViewer/JSONEditor.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | 4 | interface JSONEditorProps { 5 | value: any 6 | onChange: (value: any) => void 7 | height?: string 8 | error?: string 9 | defaultValue?: any 10 | } 11 | 12 | const JSONEditor: React.FC = ({ 13 | value, 14 | onChange, 15 | height = '200px', 16 | error, 17 | defaultValue = {} 18 | }) => { 19 | const { t } = useTranslation() 20 | const [jsonText, setJsonText] = useState('') 21 | const [localError, setLocalError] = useState('') 22 | 23 | // valueが変更されたときにテキスト表示を更新 24 | useEffect(() => { 25 | try { 26 | const formatted = JSON.stringify(value || defaultValue, null, 2) 27 | setJsonText(formatted) 28 | setLocalError('') 29 | } catch (e) { 30 | setLocalError('Invalid JSON structure') 31 | } 32 | }, [value, defaultValue]) 33 | 34 | // テキストが変更されたときの処理 35 | const handleTextChange = (e: React.ChangeEvent) => { 36 | const text = e.target.value 37 | setJsonText(text) 38 | 39 | try { 40 | const parsedValue = JSON.parse(text) 41 | onChange(parsedValue) 42 | setLocalError('') 43 | } catch (e) { 44 | setLocalError('Invalid JSON syntax') 45 | // エラーがあってもテキスト自体の更新は許可 46 | } 47 | } 48 | 49 | return ( 50 |
51 |