├── src ├── renderer │ ├── src │ │ ├── assets │ │ │ ├── base.css │ │ │ ├── main.css │ │ │ ├── images │ │ │ │ └── icons │ │ │ │ │ └── ai.svg │ │ │ └── directory-agents │ │ │ │ └── nova-sonic-voice-chat.yaml │ │ ├── components │ │ │ ├── VoiceAI │ │ │ │ ├── index.ts │ │ │ │ └── VoiceAILottie.tsx │ │ │ ├── Markdown │ │ │ │ └── styles.module.css.d.ts │ │ │ ├── Loader.tsx │ │ │ ├── Versions.tsx │ │ │ ├── WebLoader.tsx │ │ │ ├── DeepSearchButton.tsx │ │ │ ├── LocalImage │ │ │ │ └── index.tsx │ │ │ └── JSONViewer │ │ │ │ └── JSONEditor.tsx │ │ ├── pages │ │ │ ├── AgentDirectoryPage │ │ │ │ ├── index.ts │ │ │ │ └── components │ │ │ │ │ ├── ContributorModal │ │ │ │ │ └── index.ts │ │ │ │ │ ├── EmptyState.tsx │ │ │ │ │ ├── AgentDetailModal │ │ │ │ │ ├── components │ │ │ │ │ │ ├── SystemPromptSection.tsx │ │ │ │ │ │ ├── ScenariosList.tsx │ │ │ │ │ │ ├── AgentHeader.tsx │ │ │ │ │ │ └── ToolsList.tsx │ │ │ │ │ └── useAgentDetailModal.tsx │ │ │ │ │ ├── AgentList.tsx │ │ │ │ │ ├── TagFilter.tsx │ │ │ │ │ └── LoadingSkeleton.tsx │ │ │ ├── SpeakPage │ │ │ │ ├── components │ │ │ │ │ ├── PermissionHelpModal │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── VoiceSelector │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── VoiceVisual.tsx │ │ │ │ │ └── ToolResultDisplay.tsx │ │ │ │ ├── lib │ │ │ │ │ └── ObjectsExt.ts │ │ │ │ └── constants │ │ │ │ │ └── voices.ts │ │ │ ├── StepFunctionsGeneratorPage │ │ │ │ ├── aws-sfn-graph.d.ts │ │ │ │ ├── ASLEditor.tsx │ │ │ │ └── components │ │ │ │ │ └── CDKImplementButton.tsx │ │ │ ├── ChatPage │ │ │ │ ├── components │ │ │ │ │ ├── AgentForm │ │ │ │ │ │ ├── ToolsSection │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── utils │ │ │ │ │ │ │ │ ├── eventUtils.ts │ │ │ │ │ │ │ │ └── toolCategories.ts │ │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ │ └── AvailableToolsTab │ │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ │ └── CategorySelector.tsx │ │ │ │ │ │ │ └── hooks │ │ │ │ │ │ │ │ └── useToolsFormatter.ts │ │ │ │ │ │ ├── types │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── McpServerSection │ │ │ │ │ │ │ ├── utils │ │ │ │ │ │ │ │ ├── eventUtils.ts │ │ │ │ │ │ │ │ └── connectionTestUtils.ts │ │ │ │ │ │ │ └── types │ │ │ │ │ │ │ │ └── mcpServer.types.ts │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ └── formEventUtils.ts │ │ │ │ │ ├── MetadataViewer │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── CodeBlocks │ │ │ │ │ │ ├── CameraCapture │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── GuardContent │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── TextCodeBlock.tsx │ │ │ │ │ │ ├── CodeInterpreter │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── ApplyDiffEdit │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── ApplyDiffEditResult.tsx │ │ │ │ │ │ └── TavilySearch │ │ │ │ │ │ │ ├── SearchImage.tsx │ │ │ │ │ │ │ └── SearchResult.tsx │ │ │ │ │ ├── AgentList │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── EmptyState.tsx │ │ │ │ │ │ └── TagFilter.tsx │ │ │ │ │ ├── InputForm │ │ │ │ │ │ ├── ToolSettings.tsx │ │ │ │ │ │ └── DirectorySelector.tsx │ │ │ │ │ ├── MessageList │ │ │ │ │ │ └── Avatar.tsx │ │ │ │ │ ├── Recommendations │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── ModelSelector │ │ │ │ │ │ ├── claude-color.svg │ │ │ │ │ │ └── openai-color.svg │ │ │ │ │ ├── ExampleScenarios │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── InterleaveThinkingToggle │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── Code │ │ │ │ │ │ └── ResizableContainer.tsx │ │ │ │ ├── modals │ │ │ │ │ ├── useToolSettingModal │ │ │ │ │ │ ├── utils │ │ │ │ │ │ │ └── domainValidation.ts │ │ │ │ │ │ ├── PlanModeCompatibilityBadge.tsx │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── DomainTag.tsx │ │ │ │ │ │ │ ├── DomainListSection.tsx │ │ │ │ │ │ │ └── DomainInput.tsx │ │ │ │ │ │ ├── ThinkToolSettingForm.tsx │ │ │ │ │ │ └── hooks │ │ │ │ │ │ │ └── useDomainList.ts │ │ │ │ │ └── useSystemPromptModal.tsx │ │ │ │ └── hooks │ │ │ │ │ └── useAgentTools.ts │ │ │ ├── BackgroundAgentPage │ │ │ │ └── components │ │ │ │ │ ├── BackgroundAgentHelpModal │ │ │ │ │ └── index.ts │ │ │ │ │ └── TaskList │ │ │ │ │ ├── TaskCard │ │ │ │ │ ├── TaskHeader.tsx │ │ │ │ │ ├── TaskErrorDisplay.tsx │ │ │ │ │ └── TaskStatistics.tsx │ │ │ │ │ ├── atoms │ │ │ │ │ ├── AgentIcon.tsx │ │ │ │ │ ├── ToggleSwitch.tsx │ │ │ │ │ └── StatusBadge.tsx │ │ │ │ │ ├── TaskListView.tsx │ │ │ │ │ └── TaskTable │ │ │ │ │ └── TaskTableHeader.tsx │ │ │ ├── SettingPage │ │ │ │ ├── components │ │ │ │ │ ├── sections │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── ConfigDirSection.tsx │ │ │ │ │ │ ├── NotificationSection.tsx │ │ │ │ │ │ ├── LanguageSection.tsx │ │ │ │ │ │ └── ProjectSection.tsx │ │ │ │ │ └── SettingSection.tsx │ │ │ │ └── types │ │ │ │ │ └── index.ts │ │ │ ├── WebsiteGeneratorPage │ │ │ │ ├── LoadingDots.lottie.tsx │ │ │ │ ├── VoiceAI.lottie.tsx │ │ │ │ ├── LoadingWebsite.lottie.tsx │ │ │ │ ├── LoadingDataBase.lottie.tsx │ │ │ │ ├── components │ │ │ │ │ ├── RagLoader.tsx │ │ │ │ │ ├── StyleSelector.tsx │ │ │ │ │ ├── LoaderWithReasoning.tsx │ │ │ │ │ ├── Preview.tsx │ │ │ │ │ ├── TemplateButton.tsx │ │ │ │ │ ├── RecommendChanges.tsx │ │ │ │ │ └── KnowledgeBaseConnectButton.tsx │ │ │ │ ├── LazyVisibleMessage.tsx │ │ │ │ └── extensions │ │ │ │ │ └── preserveScrollPosition.ts │ │ │ ├── ErrorPage │ │ │ │ └── ErrorPage.tsx │ │ │ └── DiagramGeneratorPage │ │ │ │ └── components │ │ │ │ ├── LoaderWithReasoning.tsx │ │ │ │ ├── AWSCDKConvertButton.tsx │ │ │ │ └── ProgressBar.tsx │ │ ├── hooks │ │ │ ├── useSetting.ts │ │ │ ├── useWebsiteGeneratorSetting.ts │ │ │ ├── useScroll.ts │ │ │ ├── useAutoScroll.ts │ │ │ ├── use-debounse.ts │ │ │ ├── useToast.ts │ │ │ ├── useTheme.ts │ │ │ └── useModal.tsx │ │ ├── i18n │ │ │ ├── locales │ │ │ │ ├── agentDirectory │ │ │ │ │ └── index.ts │ │ │ │ ├── chat │ │ │ │ │ ├── guardrails.ts │ │ │ │ │ └── history.ts │ │ │ │ ├── settings │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── promptCache.ts │ │ │ │ │ ├── lightModelSettings.ts │ │ │ │ │ ├── iamPolicy.ts │ │ │ │ │ ├── notification.ts │ │ │ │ │ └── agentSettings.ts │ │ │ │ ├── planActMode.ts │ │ │ │ ├── stepFunctionGenerator │ │ │ │ │ └── index.ts │ │ │ │ └── websiteGenerator │ │ │ │ │ └── index.ts │ │ │ └── config.ts │ │ ├── main.tsx │ │ ├── constants │ │ │ └── voiceIds.ts │ │ ├── lib │ │ │ ├── util.ts │ │ │ └── modelSelection.ts │ │ └── types │ │ │ └── images.d.ts │ ├── index.css │ └── index.html ├── types │ ├── agent.ts │ ├── preload │ │ └── index.ts │ ├── chat │ │ ├── metadata.ts │ │ ├── message.ts │ │ └── history.ts │ ├── plan-mode-tools.ts │ └── electron.ts ├── main │ ├── api │ │ ├── bedrock │ │ │ ├── __tests__ │ │ │ │ └── test-assets │ │ │ │ │ └── icon.png │ │ │ ├── services │ │ │ │ ├── index.ts │ │ │ │ └── modelService.ts │ │ │ ├── types │ │ │ │ ├── claude.ts │ │ │ │ ├── structured-output.ts │ │ │ │ └── image.ts │ │ │ ├── types.ts │ │ │ └── utils │ │ │ │ └── toolGenerator.ts │ │ ├── sonic │ │ │ ├── tool-executor │ │ │ │ └── index.ts │ │ │ ├── constants.ts │ │ │ ├── types.ts │ │ │ └── consts.ts │ │ └── command │ │ │ └── types.ts │ ├── services │ │ └── strandsAgentsConverter │ │ │ └── index.ts │ ├── mcp │ │ └── command-resolver.ts │ └── handlers │ │ ├── proxy-handlers.ts │ │ └── pubsub-handlers.ts ├── preload │ ├── appWindow.ts │ ├── tools │ │ └── handlers │ │ │ ├── mcp │ │ │ └── index.ts │ │ │ ├── thinking │ │ │ └── index.ts │ │ │ ├── command │ │ │ └── index.ts │ │ │ ├── web │ │ │ └── index.ts │ │ │ ├── system │ │ │ └── index.ts │ │ │ ├── todo │ │ │ ├── index.ts │ │ │ └── types.ts │ │ │ ├── interpreter │ │ │ └── index.ts │ │ │ ├── filesystem │ │ │ └── index.ts │ │ │ └── bedrock │ │ │ └── index.ts │ ├── helpers │ │ └── agent-helpers.ts │ ├── ipc-client.ts │ ├── lib │ │ ├── random-port.ts │ │ └── gitignore-like-matcher.test.ts │ └── chat-history.ts ├── common │ ├── agents │ │ └── toolDescriptionProvider.ts │ ├── logger │ │ ├── transports │ │ │ ├── console.ts │ │ │ └── file.ts │ │ ├── config.ts │ │ └── formatters.ts │ ├── mcp │ │ ├── utils.ts │ │ └── schemas.ts │ └── utils │ │ └── placeholderUtils.ts └── test │ ├── sandbox │ └── sts.client.test.ts │ └── src │ └── preload │ └── tools.test.ts ├── .bedrock-engineer └── .ignore ├── .eslintignore ├── .prettierrc.yaml ├── .prettierignore ├── .vscode ├── extensions.json ├── settings.json └── launch.json ├── assets ├── custom-agents.png ├── custom-tools.png ├── select-agents.png ├── select-tools.png ├── agent-directory.png ├── background-agent.png ├── voice-chat-page.png ├── agent-chat-diagram.png ├── agent-chat-search.png ├── diagram-generator.png ├── website-generator.png ├── macos-security-warning-pkg.png ├── step-functions-generator.png ├── website-generator-healthcare.png ├── website-generator-data-visualization.png └── macos-security-warning-pkg-privacy-setting.png ├── dev-app-update.yml ├── .gitignore ├── docs ├── agent-directory-organization │ └── images │ │ ├── 03-s3-settings.png │ │ ├── 07-add-to-my-agents.png │ │ ├── 04-select-custom-agent.png │ │ ├── 06-agent-detail-modal.png │ │ ├── 01-organization-selector.png │ │ ├── 05-share-to-organization.png │ │ └── 02-add-organization-modal.png └── mcp-server │ └── MCP_SERVER_CONFIGURATION-ja.md ├── .editorconfig ├── tsconfig.json ├── tsconfig.test.json ├── CODE_OF_CONDUCT.md ├── .env.example ├── tsconfig.node.json ├── jest.integration.setup.js ├── jest.config.js ├── tsconfig.web.json ├── jest.integration.config.js ├── .github ├── workflows │ └── build.yml └── ISSUE_TEMPLATE │ └── feature_request.md ├── .eslintrc.cjs ├── tailwind.config.js ├── LICENSE ├── electron.vite.config.ts └── electron-builder.yml /src/renderer/src/assets/base.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.bedrock-engineer/.ignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | out 4 | .gitignore 5 | -------------------------------------------------------------------------------- /src/renderer/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | singleQuote: true 2 | semi: false 3 | printWidth: 100 4 | trailingComma: none 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | out 2 | dist 3 | pnpm-lock.yaml 4 | LICENSE.md 5 | tsconfig.json 6 | tsconfig.*.json 7 | -------------------------------------------------------------------------------- /src/renderer/src/components/VoiceAI/index.ts: -------------------------------------------------------------------------------- 1 | export { default as VoiceAILottie } from './VoiceAILottie' 2 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "lokalise.i18n-ally"] 3 | } 4 | -------------------------------------------------------------------------------- /assets/custom-agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/custom-agents.png -------------------------------------------------------------------------------- /assets/custom-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/custom-tools.png -------------------------------------------------------------------------------- /assets/select-agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/select-agents.png -------------------------------------------------------------------------------- /assets/select-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/select-tools.png -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/index.ts: -------------------------------------------------------------------------------- 1 | export { AgentDirectoryPage } from './AgentDirectoryPage' 2 | -------------------------------------------------------------------------------- /assets/agent-directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/agent-directory.png -------------------------------------------------------------------------------- /assets/background-agent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/background-agent.png -------------------------------------------------------------------------------- /assets/voice-chat-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/voice-chat-page.png -------------------------------------------------------------------------------- /src/renderer/src/pages/SpeakPage/components/PermissionHelpModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './usePermissionHelpModal' 2 | -------------------------------------------------------------------------------- /src/renderer/src/pages/StepFunctionsGeneratorPage/aws-sfn-graph.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@tshepomgaga/aws-sfn-graph' 2 | -------------------------------------------------------------------------------- /assets/agent-chat-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/agent-chat-diagram.png -------------------------------------------------------------------------------- /assets/agent-chat-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/agent-chat-search.png -------------------------------------------------------------------------------- /assets/diagram-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/diagram-generator.png -------------------------------------------------------------------------------- /assets/website-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/website-generator.png -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/ContributorModal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useContributorModal' 2 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/index.tsx: -------------------------------------------------------------------------------- 1 | export { ToolsSection } from './ToolsSection' 2 | -------------------------------------------------------------------------------- /src/types/agent.ts: -------------------------------------------------------------------------------- 1 | export type BedrockAgent = { 2 | agentId: string 3 | aliasId: string 4 | description: string 5 | } 6 | -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | provider: generic 2 | url: https://example.com/auto-updates 3 | updaterCacheDirName: bedrock-engineer-updater 4 | -------------------------------------------------------------------------------- /assets/macos-security-warning-pkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/macos-security-warning-pkg.png -------------------------------------------------------------------------------- /assets/step-functions-generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/step-functions-generator.png -------------------------------------------------------------------------------- /assets/website-generator-healthcare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/website-generator-healthcare.png -------------------------------------------------------------------------------- /src/renderer/src/assets/main.css: -------------------------------------------------------------------------------- 1 | /* @import './base.css'; */ 2 | 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/MetadataViewer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './MetadataViewer' 2 | export * from './StructuredJsonView' 3 | -------------------------------------------------------------------------------- /assets/website-generator-data-visualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/website-generator-data-visualization.png -------------------------------------------------------------------------------- /src/renderer/src/components/Markdown/styles.module.css.d.ts: -------------------------------------------------------------------------------- 1 | declare const styles: { 2 | readonly reactMarkDown: string 3 | } 4 | 5 | export default styles 6 | -------------------------------------------------------------------------------- /src/main/api/bedrock/__tests__/test-assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/src/main/api/bedrock/__tests__/test-assets/icon.png -------------------------------------------------------------------------------- /src/renderer/src/hooks/useSetting.ts: -------------------------------------------------------------------------------- 1 | // Re-export the useSettings hook from the context 2 | export { useSettings as default } from '../contexts/SettingsContext' 3 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/BackgroundAgentHelpModal/index.ts: -------------------------------------------------------------------------------- 1 | export { useBackgroundAgentHelpModal } from './useBackgroundAgentHelpModal' 2 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SpeakPage/components/VoiceSelector/index.ts: -------------------------------------------------------------------------------- 1 | export { VoiceSelector } from './VoiceSelector' 2 | export { VoiceVisual } from './VoiceVisual' 3 | -------------------------------------------------------------------------------- /.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 | 13 | -------------------------------------------------------------------------------- /assets/macos-security-warning-pkg-privacy-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/assets/macos-security-warning-pkg-privacy-setting.png -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/03-s3-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/03-s3-settings.png -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/agentDirectory/index.ts: -------------------------------------------------------------------------------- 1 | import { en } from './en' 2 | import { ja } from './ja' 3 | 4 | export const agentDirectory = { 5 | en, 6 | ja 7 | } 8 | -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/07-add-to-my-agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/07-add-to-my-agents.png -------------------------------------------------------------------------------- /src/main/api/sonic/tool-executor/index.ts: -------------------------------------------------------------------------------- 1 | export { SonicToolExecutor } from './SonicToolExecutor' 2 | export type { ToolExecutionResponse, ToolExecutionRequest } from './SonicToolExecutor' 3 | -------------------------------------------------------------------------------- /src/preload/appWindow.ts: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron' 2 | 3 | export const appWindow = { 4 | isFocused: (): Promise => ipcRenderer.invoke('window:isFocused') 5 | } 6 | -------------------------------------------------------------------------------- /src/types/preload/index.ts: -------------------------------------------------------------------------------- 1 | import { file } from '../../preload/file' 2 | 3 | declare global { 4 | interface Window { 5 | file: typeof file 6 | } 7 | } 8 | 9 | export {} 10 | -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/04-select-custom-agent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/04-select-custom-agent.png -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/06-agent-detail-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/06-agent-detail-modal.png -------------------------------------------------------------------------------- /src/types/chat/metadata.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * メッセージIDとメタデータIDを生成するための関数 3 | */ 4 | export const generateMessageId = (): string => 5 | `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}` 6 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/01-organization-selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/01-organization-selector.png -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/05-share-to-organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/05-share-to-organization.png -------------------------------------------------------------------------------- /src/renderer/src/hooks/useWebsiteGeneratorSetting.ts: -------------------------------------------------------------------------------- 1 | // Re-export the useSettings hook from the context 2 | export { useWebsiteGeneratorSetting as default } from '../contexts/WebsiteGeneratorContext' 3 | -------------------------------------------------------------------------------- /docs/agent-directory-organization/images/02-add-organization-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/bedrock-engineer/HEAD/docs/agent-directory-organization/images/02-add-organization-modal.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }], 4 | "compilerOptions": { "types": ["vite-plugin-svgr/client"] }, 5 | } 6 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/CameraCapture/index.ts: -------------------------------------------------------------------------------- 1 | export { CameraCaptureResult } from './CameraCaptureResult' 2 | export type { CameraCaptureResponse } from './CameraCaptureResult' 3 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentList/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AgentList' 2 | export * from './AgentCard' 3 | export * from './EmptyState' 4 | export * from './TagFilter' 5 | export * from './useAgentFilter' 6 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/GuardContent/index.ts: -------------------------------------------------------------------------------- 1 | import { GuardContent, GuardContentCollapsible } from './GuardContent' 2 | 3 | export { GuardContent, GuardContentCollapsible } 4 | export default GuardContent 5 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/chat/guardrails.ts: -------------------------------------------------------------------------------- 1 | export const guardrails = { 2 | en: { 3 | 'guardrail.intervention': 'Guardrail Intervation' 4 | }, 5 | ja: { 6 | 'guardrail.intervention': 'Guardrail による介入を検出しました' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/api/bedrock/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './converseService' 2 | export * from './imageRecognitionService' 3 | export * from './flowService' 4 | export * from './translateService' 5 | export * from './movieService' 6 | export * from './inferenceProfileService' 7 | -------------------------------------------------------------------------------- /src/common/agents/toolDescriptionProvider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Tool description provider interface 3 | * Provides detailed tool descriptions for system prompt generation 4 | */ 5 | export interface IToolDescriptionProvider { 6 | getToolDescription(toolName: string): string | Promise 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.node.json", 3 | "compilerOptions": { 4 | "esModuleInterop": true, 5 | "types": ["jest", "node"], 6 | "module": "CommonJS", 7 | "moduleResolution": "node" 8 | }, 9 | "include": ["src/**/*.test.ts", "src/**/*.integration.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/index.ts: -------------------------------------------------------------------------------- 1 | export * from './iamPolicy' 2 | export * from './notification' 3 | export * from './bedrock' 4 | export * from './agentSettings' 5 | export * from './agentToolsSettings' 6 | export * from './promptCache' 7 | export * from './tokenAnalytics' 8 | export * from './lightModelSettings' 9 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/sections/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProjectSection' 2 | export * from './LanguageSection' 3 | export * from './AgentChatSection' 4 | export * from './AWSSection' 5 | export * from './AdvancedSection' 6 | export * from './NotificationSection' 7 | export * from './GuardrailSettings' 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/renderer/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import '../index.css' 5 | import './i18n/config' 6 | 7 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 8 | 9 | 10 | 11 | ) 12 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/TextCodeBlock.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const TextCodeBlock: React.FC<{ text: string }> = ({ text }) => { 4 | return ( 5 |
 6 |       {text}
 7 |     
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/renderer/src/constants/voiceIds.ts: -------------------------------------------------------------------------------- 1 | // Available voice IDs for Sonic API 2 | export const VOICE_OPTIONS = [ 3 | { value: 'amy', label: 'Amy' }, 4 | { value: 'matthew', label: 'Matthew' }, 5 | { value: 'tiffany', label: 'Tiffany' } 6 | ] as const 7 | 8 | export type VoiceId = (typeof VOICE_OPTIONS)[number]['value'] 9 | 10 | export const DEFAULT_VOICE_ID: VoiceId = 'amy' 11 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@electron-toolkit/tsconfig/tsconfig.node.json", 3 | "include": [ 4 | "electron.vite.config.*", 5 | "src/main/**/*", 6 | "src/preload/**/*", 7 | "src/types/**/*", 8 | "src/test/**/*", 9 | "src/common/**/*" 10 | ], 11 | "compilerOptions": { 12 | "composite": true, 13 | "types": ["electron-vite/node", "jest"] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/types/index.ts: -------------------------------------------------------------------------------- 1 | import { CustomAgent } from '@/types/agent-chat' 2 | 3 | /** 4 | * エージェントフォームのタブID型定義 5 | */ 6 | export type AgentFormTabId = 'basic' | 'mcp-servers' | 'tools' 7 | 8 | /** 9 | * エージェントフォームのプロパティ型定義 10 | */ 11 | export interface AgentFormProps { 12 | agent?: CustomAgent 13 | onSave: (agent: CustomAgent) => void 14 | onCancel: () => void 15 | } 16 | -------------------------------------------------------------------------------- /src/renderer/src/components/Loader.tsx: -------------------------------------------------------------------------------- 1 | type LoaderProps = { 2 | text?: string 3 | } 4 | 5 | export const Loader = (props: LoaderProps) => { 6 | return ( 7 |
8 |
9 | {props?.text || 'loading...'} 10 |
11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/renderer/src/lib/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 複数のクラス名を組み合わせるユーティリティ関数 3 | * tailwindcss の clsxとtwMergeをインスパイアした簡易版 4 | * 5 | * @param classes 結合したいクラス名(条件付きで追加できる) 6 | * @returns 結合されたクラス名の文字列 7 | */ 8 | export function cn(...classes: (string | boolean | undefined | null)[]): string { 9 | return classes.filter(Boolean).join(' ').trim() 10 | } 11 | 12 | export const sleep = (msec: number) => new Promise((resolve) => setTimeout(resolve, msec)) 13 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/CodeInterpreter/index.ts: -------------------------------------------------------------------------------- 1 | export { CodeInterpreterResult } from './CodeInterpreterResult' 2 | export { ExecutedCodeBlock } from './ExecutedCodeBlock' 3 | export { OutputDisplay } from './OutputDisplay' 4 | export { FileDisplay } from './FileDisplay' 5 | export { ErrorDisplay } from './ErrorDisplay' 6 | export { ExecutionMetadata } from './ExecutionMetadata' 7 | export { ImagePreview } from './ImagePreview' 8 | -------------------------------------------------------------------------------- /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/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/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/renderer/src/pages/WebsiteGeneratorPage/LoadingDots.lottie.tsx: -------------------------------------------------------------------------------- 1 | import Lottie, { LottieComponentProps } from 'lottie-react' 2 | import data from '../../assets/lottie/loading-dots.json' 3 | 4 | // ignore type animationData from LottieComponentProps 5 | type LoadingDotsLottieProps = Omit 6 | 7 | const LoadingDotsLottie = (props?: LoadingDotsLottieProps) => { 8 | return 9 | } 10 | 11 | export default LoadingDotsLottie 12 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/VoiceAI.lottie.tsx: -------------------------------------------------------------------------------- 1 | import Lottie, { LottieComponentProps } from 'lottie-react' 2 | import data from '../../assets/lottie/loading-voice-with-ai.json' 3 | 4 | // ignore type animationData from LottieComponentProps 5 | type LoadingDotsLottieProps = Omit 6 | 7 | const VoiceAILottie = (props?: LoadingDotsLottieProps) => { 8 | return 9 | } 10 | 11 | export default VoiceAILottie 12 | -------------------------------------------------------------------------------- /src/types/plan-mode-tools.ts: -------------------------------------------------------------------------------- 1 | import { ToolName } from './tools' 2 | 3 | // Planモードで実行可能なツール名のリスト 4 | export const READ_ONLY_TOOLS: ToolName[] = [ 5 | 'readFiles', 6 | 'listFiles', 7 | 'tavilySearch', 8 | 'fetchWebsite', 9 | 'recognizeImage', 10 | 'retrieve', 11 | 'invokeBedrockAgent', 12 | 'think' 13 | ] 14 | 15 | // ツールがPlanモードで使用可能かどうかを判定する関数 16 | export const isPlanModeCompatible = (toolName: string): boolean => { 17 | return READ_ONLY_TOOLS.includes(toolName as ToolName) 18 | } 19 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SpeakPage/lib/ObjectsExt.ts: -------------------------------------------------------------------------------- 1 | export class ObjectExt { 2 | static exists(obj: unknown): boolean { 3 | return obj !== undefined && obj !== null 4 | } 5 | 6 | static checkArgument(condition: boolean, message: string): void { 7 | if (!condition) { 8 | throw new TypeError(message) 9 | } 10 | } 11 | 12 | static checkExists(obj: unknown, message: string): void { 13 | if (!ObjectExt.exists(obj)) { 14 | throw new TypeError(message) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/renderer/src/components/Versions.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | function Versions(): JSX.Element { 4 | const [versions] = useState(window.electron.process.versions) 5 | 6 | return ( 7 |
    8 |
  • Electron v{versions.electron}
  • 9 |
  • Chromium v{versions.chrome}
  • 10 |
  • Node v{versions.node}
  • 11 |
12 | ) 13 | } 14 | 15 | export default Versions 16 | -------------------------------------------------------------------------------- /src/test/sandbox/sts.client.test.ts: -------------------------------------------------------------------------------- 1 | import { GetCallerIdentityCommand, STSClient } from '@aws-sdk/client-sts' 2 | import { test } from '@jest/globals' 3 | 4 | const getAccountId = async () => { 5 | const client = new STSClient() 6 | const command = new GetCallerIdentityCommand({}) 7 | const res = await client.send(command) 8 | console.log(res) 9 | return res.Account 10 | } 11 | 12 | test.skip('getAccountId', async () => { 13 | const accountId = await getAccountId() 14 | console.log(accountId) 15 | }) 16 | -------------------------------------------------------------------------------- /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/renderer/src/pages/WebsiteGeneratorPage/LoadingWebsite.lottie.tsx: -------------------------------------------------------------------------------- 1 | import Lottie, { LottieComponentProps } from 'lottie-react' 2 | import data from '../../assets/lottie/loading-website.json' 3 | 4 | // ignore type animationData from LottieComponentProps 5 | type LoadingWebsiteLottieProps = Omit 6 | 7 | const LoadingWebsiteLottie = (props?: LoadingWebsiteLottieProps) => { 8 | return 9 | } 10 | 11 | export default LoadingWebsiteLottie 12 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/LoadingDataBase.lottie.tsx: -------------------------------------------------------------------------------- 1 | import Lottie, { LottieComponentProps } from 'lottie-react' 2 | import data from '../../assets/lottie/loading-database.json' 3 | 4 | // ignore type animationData from LottieComponentProps 5 | type LoadingDataBaseLottieProps = Omit 6 | 7 | const LoadingDataBaseLottie = (props?: LoadingDataBaseLottieProps) => { 8 | return 9 | } 10 | 11 | export default LoadingDataBaseLottie 12 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/promptCache.ts: -------------------------------------------------------------------------------- 1 | export const promptCacheSettings = { 2 | en: { 3 | 'Enable Prompt Cache': 'Enable Prompt Cache', 4 | 'Prompt Cache reduces token usage by caching parts of the conversation': 5 | 'Prompt Cache reduces token usage by caching parts of the conversation' 6 | }, 7 | ja: { 8 | 'Enable Prompt Cache': 'プロンプトキャッシュを有効にする', 9 | 'Prompt Cache reduces token usage by caching parts of the conversation': 10 | 'プロンプトキャッシュは会話の一部をキャッシュすることでトークン使用量を削減します' 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/renderer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bedrock Engineer 6 | 7 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/renderer/src/hooks/useScroll.ts: -------------------------------------------------------------------------------- 1 | const useScroll = () => { 2 | return { 3 | scrollToTop: (elementId: string = 'main') => { 4 | document.getElementById(elementId)?.scrollTo({ 5 | top: 0, 6 | behavior: 'smooth' 7 | }) 8 | }, 9 | scrollToBottom: (elementId: string = 'main') => { 10 | document.getElementById(elementId)?.scrollTo({ 11 | top: document.getElementById(elementId)?.scrollHeight, 12 | behavior: 'smooth' 13 | }) 14 | } 15 | } 16 | } 17 | 18 | export default useScroll 19 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} **/ 2 | module.exports = { 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | transform: { 6 | '^.+.tsx?$': [ 7 | 'ts-jest', 8 | { 9 | tsconfig: 'tsconfig.test.json' 10 | } 11 | ] 12 | }, 13 | testMatch: ['**/*.test.ts'], 14 | testPathIgnorePatterns: [ 15 | '/node_modules/', 16 | '\\.integration\\.test\\.ts$' // .integration.test.ts で終わるファイルを除外 17 | ], 18 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'] 19 | } 20 | -------------------------------------------------------------------------------- /src/renderer/src/hooks/useAutoScroll.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from 'react' 2 | 3 | /** 4 | * Auto-scroll hook that automatically scrolls to the bottom of a container 5 | * when dependencies change 6 | */ 7 | export const useAutoScroll = (dependencies: unknown[]) => { 8 | const chatContainerRef = useRef(null) 9 | 10 | useEffect(() => { 11 | if (chatContainerRef.current) { 12 | chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight 13 | } 14 | }, dependencies) 15 | 16 | return { chatContainerRef } 17 | } 18 | -------------------------------------------------------------------------------- /src/types/chat/message.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Message as BedrockMessage, 3 | ConverseStreamMetadataEvent 4 | } from '@aws-sdk/client-bedrock-runtime' 5 | 6 | /** 7 | * IDを持つメッセージ型 8 | * AWS Bedrockのメッセージ型を拡張して、メッセージIDとメタデータを追加 9 | */ 10 | export interface IdentifiableMessage extends BedrockMessage { 11 | id?: string 12 | status?: 'idle' | 'streaming' | 'complete' | 'error' 13 | timestamp?: number 14 | metadata?: { 15 | converseMetadata?: ConverseStreamMetadataEvent | Record 16 | sessionCost?: number 17 | // 将来的に他のメタデータタイプも追加可能 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/config.ts: -------------------------------------------------------------------------------- 1 | import i18n from 'i18next' 2 | import { initReactI18next } from 'react-i18next' 3 | import en from './locales/en' 4 | import ja from './locales/ja' 5 | 6 | const defaultLaunguage = window.store.get('language') ?? navigator.language 7 | 8 | const resources = { 9 | en: { 10 | translation: en 11 | }, 12 | ja: { 13 | translation: ja 14 | } 15 | } 16 | 17 | i18n.use(initReactI18next).init({ 18 | resources, 19 | lng: defaultLaunguage, 20 | interpolation: { 21 | escapeValue: false 22 | } 23 | }) 24 | 25 | export default i18n 26 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/ApplyDiffEdit/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Props for the DiffViewer component 3 | */ 4 | export interface DiffViewerProps { 5 | originalText: string 6 | updatedText: string 7 | filePath: string 8 | language?: string 9 | } 10 | 11 | /** 12 | * Props for ApplyDiffEditResult component 13 | */ 14 | export interface ApplyDiffEditResultProps { 15 | response: { 16 | success: boolean 17 | error?: string 18 | result?: { 19 | path: string 20 | originalText: string 21 | updatedText: string 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.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": ["src/renderer/src/i18n", "src/renderer/src/i18n/locales"], 14 | "i18n-ally.enabledParsers": ["ts"], 15 | "i18n-ally.keystyle": "nested", 16 | "i18n-ally.displayLanguage": "ja" 17 | } 18 | -------------------------------------------------------------------------------- /src/renderer/src/types/images.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: string 3 | export default content 4 | } 5 | 6 | declare module '*.png' { 7 | const content: string 8 | export default content 9 | } 10 | 11 | declare module '*.jpg' { 12 | const content: string 13 | export default content 14 | } 15 | 16 | declare module '*.jpeg' { 17 | const content: string 18 | export default content 19 | } 20 | 21 | declare module '*.gif' { 22 | const content: string 23 | export default content 24 | } 25 | 26 | declare module '*.webp' { 27 | const content: string 28 | export default content 29 | } 30 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/components/RagLoader.tsx: -------------------------------------------------------------------------------- 1 | import LazyVisibleMessage from '../LazyVisibleMessage' 2 | import LoadingDataBaseLottie from '../LoadingDataBase.lottie' 3 | 4 | export const RagLoader = () => { 5 | return ( 6 |
7 | 8 | Connecting datasource... 9 | 10 | 11 | 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.web.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@electron-toolkit/tsconfig/tsconfig.web.json", 3 | "include": [ 4 | "src/renderer/src/env.d.ts", 5 | "src/renderer/src/**/*", 6 | "src/renderer/src/**/*.tsx", 7 | "src/preload/*.d.ts", 8 | "src/types/*.d.ts", 9 | "src/types/**/*.ts", 10 | "src/common/**/*" 11 | ], 12 | "compilerOptions": { 13 | "composite": true, 14 | "jsx": "react-jsx", 15 | "baseUrl": ".", 16 | "paths": { 17 | "@renderer/*": ["src/renderer/src/*"], 18 | "@/*": ["src/*"], 19 | "@types/*": ["src/types/*"], 20 | "@common/*": ["src/common/*"] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/chat/history.ts: -------------------------------------------------------------------------------- 1 | export const history = { 2 | en: { 3 | 'Chat History': 'Chat History', 4 | 'Edit title': 'Edit title', 5 | Delete: 'Delete', 6 | 'No chat history': 'No chat history', 7 | 'Generate title': 'Geneate title', 8 | 'Generate All Titles': 'Generate All Titles', 9 | 'Delete All': 'Delete All' 10 | }, 11 | ja: { 12 | 'Chat History': 'チャット履歴', 13 | 'Edit title': '名前を変更する', 14 | Delete: '削除する', 15 | 'No chat history': 'チャット履歴はありません', 16 | 'Generate title': '名前を生成する', 17 | 'Generate All Titles': '全ての名前を生成する', 18 | 'Delete All': '全て削除する' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/TavilySearch/SearchImage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface Props { 4 | url: string 5 | } 6 | 7 | export const SearchImage: React.FC = ({ url }) => { 8 | const handleImageClick = () => { 9 | open(url) 10 | } 11 | 12 | return ( 13 |
17 | Search result 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /src/renderer/src/components/WebLoader.tsx: -------------------------------------------------------------------------------- 1 | import LazyVisibleMessage from '../pages/WebsiteGeneratorPage/LazyVisibleMessage' 2 | import LoadingWebsiteLottie from '../pages/WebsiteGeneratorPage/LoadingWebsite.lottie' 3 | 4 | export const WebLoader = () => { 5 | return ( 6 |
7 | 8 | Searching websites... 9 | 10 | 11 | 12 |
13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/TaskCard/TaskHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { StatusBadge } from '../atoms/StatusBadge' 3 | 4 | interface TaskHeaderProps { 5 | name: string 6 | hasError?: boolean 7 | } 8 | 9 | export const TaskHeader: React.FC = ({ name, hasError }) => { 10 | return ( 11 |
12 |

{name}

13 | {/* Show status badge only for error state */} 14 | {hasError && エラー} 15 |
16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/McpServerSection/utils/eventUtils.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * モーダルを閉じないようにするためのイベントハンドラ 5 | * @param e イベントオブジェクト 6 | */ 7 | export function preventModalClose(e: React.MouseEvent): void { 8 | e.preventDefault() 9 | e.stopPropagation() 10 | } 11 | 12 | /** 13 | * イベントハンドラをラップして preventModalClose を適用する 14 | * @param handler 元のイベントハンドラ 15 | * @returns {Function} ラップされたイベントハンドラ 16 | */ 17 | export function withPreventClose( 18 | handler: (e: T) => void 19 | ): (e: T) => void { 20 | return (e: T) => { 21 | preventModalClose(e) 22 | handler(e) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /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/renderer/src/hooks/use-debounse.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | export function useDebounce(value: any, delay: number) { 4 | // debounce の対象 state と setter 5 | const [debouncedValue, setDebouncedValue] = useState(value) 6 | 7 | useEffect(() => { 8 | // delay 後 debounce の対象 state をアップデート 9 | const timer = setTimeout(() => { 10 | setDebouncedValue(value) 11 | }, delay) 12 | 13 | // 次の effect が実行される直前に timer キャンセル 14 | return () => { 15 | clearTimeout(timer) 16 | } 17 | 18 | // value、delay がアップデートするたびに effect 実行 19 | }, [value, delay]) 20 | 21 | // 最終的にアップデートされた state をリターン 22 | return debouncedValue 23 | } 24 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/InputForm/ToolSettings.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { FcSupport } from 'react-icons/fc' 3 | 4 | type ToolSettingsProps = { 5 | onOpenToolSettings: () => void 6 | } 7 | 8 | export const ToolSettings: React.FC = ({ onOpenToolSettings }) => { 9 | return ( 10 | 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /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 | // Run tests in parallel across multiple workers for faster execution 20 | maxWorkers: '50%' // Use 50% of available CPU cores 21 | } 22 | -------------------------------------------------------------------------------- /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/src/pages/ChatPage/modals/useToolSettingModal/utils/domainValidation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Validates a domain string according to Tavily's domain format requirements. 3 | * 4 | * Supported formats: 5 | * - Standard domains: example.com 6 | * - Wildcards: *.com, *.example.com 7 | * - Paths: linkedin.com/in, example.com/path/to/page 8 | * 9 | * @param domain - The domain string to validate 10 | * @returns true if the domain is valid, false otherwise 11 | */ 12 | export const validateDomain = (domain: string): boolean => { 13 | const domainRegex = 14 | /^(\*\.)?[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,})(\/[^\s]*)?$/ 15 | return domainRegex.test(domain.trim()) 16 | } 17 | -------------------------------------------------------------------------------- /src/renderer/src/components/VoiceAI/VoiceAILottie.tsx: -------------------------------------------------------------------------------- 1 | import Lottie, { LottieComponentProps } from 'lottie-react' 2 | import data from '../../assets/lottie/loading-voice-with-ai.json' 3 | 4 | // ignore type animationData from LottieComponentProps 5 | type VoiceAILottieProps = Omit & { 6 | // 音声切り替え時のアニメーション再実行のためのキー 7 | voiceKey?: string | number 8 | } 9 | 10 | const VoiceAILottie = ({ voiceKey, ...props }: VoiceAILottieProps) => { 11 | return ( 12 | 19 | ) 20 | } 21 | 22 | export default VoiceAILottie 23 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/system/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * System tools exports 3 | */ 4 | 5 | export { ScreenCaptureTool } from './ScreenCaptureTool' 6 | export { CameraCaptureTool } from './CameraCaptureTool' 7 | 8 | import type { ToolDependencies } from '../../base/types' 9 | import { ScreenCaptureTool } from './ScreenCaptureTool' 10 | import { CameraCaptureTool } from './CameraCaptureTool' 11 | 12 | /** 13 | * Factory function to create all system tools 14 | */ 15 | export function createSystemTools(dependencies: ToolDependencies) { 16 | return [ 17 | { tool: new ScreenCaptureTool(dependencies), category: 'system' as const }, 18 | { tool: new CameraCaptureTool(dependencies), category: 'system' as const } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/common/mcp/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * MCP関連の共通ユーティリティ関数 3 | */ 4 | 5 | import { McpServerConfig } from '../../types/agent-chat' 6 | 7 | /** 8 | * ConnectionTypeを自動推測する関数(後方互換性用) 9 | * @param server MCPサーバー設定 10 | * @returns 推測されたconnectionType 11 | */ 12 | export function inferConnectionType(server: McpServerConfig): 'command' | 'url' { 13 | // connectionTypeが既に設定されている場合はそのまま使用 14 | if (server.connectionType) { 15 | return server.connectionType 16 | } 17 | 18 | // commandフィールドが存在する場合はcommand形式 19 | if (server.command) { 20 | return 'command' 21 | } 22 | 23 | // urlフィールドが存在する場合はurl形式 24 | if (server.url) { 25 | return 'url' 26 | } 27 | 28 | // デフォルトはcommand形式(旧形式との互換性) 29 | return 'command' 30 | } 31 | -------------------------------------------------------------------------------- /src/main/services/strandsAgentsConverter/index.ts: -------------------------------------------------------------------------------- 1 | // Main exports for Strands Agents conversion service 2 | export { StrandsAgentsConverter } from './StrandsAgentsConverter' 3 | export { CodeGenerator } from './codeGenerator' 4 | export { TOOL_MAPPING } from './toolMapper' 5 | export type { 6 | StrandsTool, 7 | ToolMappingResult, 8 | AgentConfig, 9 | CodeGenerationParams, 10 | StrandsAgentOutput, 11 | TemplateVariables 12 | } from './types' 13 | export { 14 | PYTHON_AGENT_TEMPLATE, 15 | REQUIREMENTS_TEMPLATE, 16 | CONFIG_TEMPLATE, 17 | README_TEMPLATE, 18 | renderTemplate, 19 | generateToolsSetupCode, 20 | combineSpecialSetupCode, 21 | generateYamlList, 22 | generateEnvironmentSetup 23 | } from './templateEngine' 24 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/components/StyleSelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Dropdown } from 'flowbite-react' 3 | import { Style } from '../templates' 4 | 5 | interface StyleSelectorProps { 6 | currentStyle: Style 7 | styles: Style[] 8 | onSelect: (style: Style) => void 9 | } 10 | 11 | export const StyleSelector: React.FC = ({ currentStyle, styles, onSelect }) => { 12 | return ( 13 | 14 | {styles?.map((style) => ( 15 | onSelect(style)}> 16 | {style.label} 17 | 18 | ))} 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/main/api/sonic/constants.ts: -------------------------------------------------------------------------------- 1 | // Nova 2 Sonic supported regions 2 | export const NOVA_SONIC_SUPPORTED_REGIONS = [ 3 | 'us-east-1', // 米国東部 (バージニア北部) 4 | 'us-west-2' // 米国西部 (オレゴン) 5 | ] as const 6 | 7 | export type NovaSonicSupportedRegion = (typeof NOVA_SONIC_SUPPORTED_REGIONS)[number] 8 | 9 | /** 10 | * Check if the given region supports Nova Sonic 11 | */ 12 | export function isNovaSonicSupportedRegion(region: string): region is NovaSonicSupportedRegion { 13 | return NOVA_SONIC_SUPPORTED_REGIONS.includes(region as NovaSonicSupportedRegion) 14 | } 15 | 16 | /** 17 | * Get the list of supported regions for Nova Sonic 18 | */ 19 | export function getNovaSonicSupportedRegions(): readonly string[] { 20 | return NOVA_SONIC_SUPPORTED_REGIONS 21 | } 22 | -------------------------------------------------------------------------------- /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: (channel: C, ...args: any[]): Promise> => { 10 | return ipcRenderer.invoke(channel, ...args) 11 | } 12 | } 13 | } 14 | 15 | /** 16 | * Preload用の型安全なIPC呼び出し関数 17 | * シンプルで使いやすいAPI 18 | */ 19 | export function ipc( 20 | channel: C, 21 | params: IPCParams 22 | ): Promise> { 23 | return ipcRenderer.invoke(channel, params) as Promise> 24 | } 25 | 26 | // renderer用に公開するAPIオブジェクト 27 | export const ipcClient = createIpcClient() 28 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SpeakPage/components/VoiceSelector/VoiceVisual.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { VoiceId } from '../../constants/voices' 3 | import { VoiceAILottie } from '@renderer/components/VoiceAI' 4 | 5 | interface VoiceVisualProps { 6 | voiceId: VoiceId 7 | // アニメーション再実行のためのキー 8 | animationKey?: string | number 9 | } 10 | 11 | export const VoiceVisual: React.FC = ({ voiceId, animationKey }) => { 12 | return ( 13 |
14 | 19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/PlanModeCompatibilityBadge.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { isPlanModeCompatible } from '@/types/plan-mode-tools' 3 | 4 | interface PlanModeCompatibilityBadgeProps { 5 | toolName: string 6 | } 7 | 8 | export const PlanModeCompatibilityBadge: React.FC = ({ 9 | toolName 10 | }) => { 11 | const isPlanCompatible = isPlanModeCompatible(toolName) 12 | 13 | // Planモード非対応のツールの場合のみバッジを表示 14 | if (!isPlanCompatible) { 15 | return ( 16 | 17 | Act only 18 | 19 | ) 20 | } 21 | 22 | // Planモード対応のツールの場合は何も表示しない 23 | return null 24 | } 25 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/lightModelSettings.ts: -------------------------------------------------------------------------------- 1 | export const lightModelSettings = { 2 | en: { 3 | 'settings.lightModel.title': 'Light Processing Model', 4 | 'settings.lightModel.description': 5 | 'Select a model to use for lighter tasks like generating chat titles and recommendations.', 6 | 'settings.lightModel.useMain': 'Use Main Conversation Model', 7 | 'settings.lightModel.info': 'Using smaller models for these tasks can reduce cost and latency.' 8 | }, 9 | ja: { 10 | 'settings.lightModel.title': '軽量処理用モデル', 11 | 'settings.lightModel.description': 12 | 'チャットタイトル生成などの軽微な処理に使用するモデルを選択します。', 13 | 'settings.lightModel.useMain': 'メイン会話モデルを使用', 14 | 'settings.lightModel.info': 15 | 'これらのタスクに小さなモデルを使用すると、コストとレイテンシを削減できます。' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ErrorPage/ErrorPage.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from 'flowbite-react' 2 | import toast from 'react-hot-toast' 3 | import { useRouteError } from 'react-router' 4 | import { Link } from 'react-router-dom' 5 | 6 | const ErrorPage = () => { 7 | const error = useRouteError() 8 | console.error({ error }) 9 | toast.error('Oops! Something went wrong.') 10 | 11 | return ( 12 |
13 |

Oops!

14 |
Error: {JSON.stringify(error)}
15 | 16 | 17 | 18 |
19 | ) 20 | } 21 | export default ErrorPage 22 | -------------------------------------------------------------------------------- /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/preload/tools/handlers/todo/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Todo tools exports 3 | */ 4 | 5 | import { ToolDependencies, ITool, ToolCategory } from '../../base/types' 6 | import { TodoInitTool } from './TodoInitTool' 7 | import { TodoUpdateTool } from './TodoUpdateTool' 8 | 9 | export { TodoInitTool } from './TodoInitTool' 10 | export { TodoUpdateTool } from './TodoUpdateTool' 11 | export * from './types' 12 | 13 | /** 14 | * Create todo tools 15 | */ 16 | export function createTodoTools(dependencies: ToolDependencies): Array<{ 17 | tool: ITool 18 | category: ToolCategory 19 | }> { 20 | return [ 21 | { 22 | tool: new TodoInitTool(dependencies), 23 | category: 'thinking' as ToolCategory 24 | }, 25 | { 26 | tool: new TodoUpdateTool(dependencies), 27 | category: 'thinking' as ToolCategory 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/renderer/src/lib/modelSelection.ts: -------------------------------------------------------------------------------- 1 | import { LLM } from '@/types/llm' 2 | import { useSettings } from '@renderer/contexts/SettingsContext' 3 | 4 | /** 5 | * 軽量処理用のモデルIDを取得する 6 | * 軽量モデルが設定されていない場合はフォールバックモデルを返す 7 | */ 8 | export function getLightProcessingModelId( 9 | currentLLM: LLM, 10 | lightProcessingModel: LLM | null 11 | ): string { 12 | // 軽量処理用モデルが設定されている場合はそれを返す 13 | if (lightProcessingModel && lightProcessingModel.modelId) { 14 | return lightProcessingModel.modelId 15 | } 16 | 17 | // 設定されていない場合は現在のモデルを使用する 18 | return currentLLM?.modelId 19 | } 20 | 21 | /** 22 | * 軽量処理用モデルを使用するためのカスタムフック 23 | */ 24 | export function useLightProcessingModel() { 25 | const { currentLLM, lightProcessingModel } = useSettings() 26 | 27 | return { 28 | getLightModelId: () => getLightProcessingModelId(currentLLM, lightProcessingModel) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { TbSearchOff } from 'react-icons/tb' 4 | 5 | export const EmptyState: React.FC = () => { 6 | const { t } = useTranslation() 7 | 8 | return ( 9 |
10 |
11 | 12 |
13 |

14 | {t('noAgentsFound')} 15 |

16 |

17 | {t('tryDifferentSearch')} 18 |

19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentList/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { TbSearchOff } from 'react-icons/tb' 4 | 5 | export const EmptyState: React.FC = () => { 6 | const { t } = useTranslation() 7 | 8 | return ( 9 |
10 |
11 | 12 |
13 |

14 | {t('noAgentsFound')} 15 |

16 |

17 | {t('tryDifferentSearch')} 18 |

19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /.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 | env: 15 | NODE_OPTIONS: '--max-old-space-size=8192' # メモリ制限を8GBに設定 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Use Node.js 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 20 23 | 24 | - name: Install dependencies 25 | run: npm ci 26 | 27 | - name: Lint 28 | run: npm run lint 29 | 30 | - name: Type check 31 | run: npm run typecheck 32 | 33 | - name: Run unit tests 34 | run: npm test -- --coverage 35 | 36 | - name: Build app 37 | run: npm run build:${{ matrix.os == 'windows-latest' && 'win' || 'mac' }} 38 | -------------------------------------------------------------------------------- /src/renderer/src/hooks/useToast.ts: -------------------------------------------------------------------------------- 1 | import { toastService, ToastOptions } from '@renderer/services/ToastService' 2 | 3 | export const useToast = () => { 4 | return { 5 | success: (message: string, options?: ToastOptions) => { 6 | return toastService.success(message, options) 7 | }, 8 | 9 | error: (message: string, options?: ToastOptions) => { 10 | return toastService.error(message, options) 11 | }, 12 | 13 | info: (message: string, options?: ToastOptions) => { 14 | return toastService.info(message, options) 15 | }, 16 | 17 | loading: (message: string, options?: ToastOptions) => { 18 | return toastService.loading(message, options) 19 | }, 20 | 21 | // ユーティリティメソッド 22 | dismiss: (toastId?: string) => { 23 | toastService.dismiss(toastId) 24 | }, 25 | 26 | dismissAll: () => { 27 | toastService.dismissAll() 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/AgentDetailModal/components/SystemPromptSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | 4 | interface SystemPromptSectionProps { 5 | systemPrompt: string 6 | } 7 | 8 | export const SystemPromptSection: React.FC = ({ systemPrompt }) => { 9 | const { t } = useTranslation() 10 | 11 | return ( 12 |
13 |

14 | {t('systemPromptLabel')} 15 |

16 |
17 |
18 |           {systemPrompt}
19 |         
20 |
21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/types/electron.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from '@aws-sdk/client-bedrock-runtime' 2 | import { ElectronAPI } from '@electron-toolkit/preload' 3 | import { chatHistory } from '../preload/chat-history' 4 | import { ConfigStore } from '../preload/store' 5 | import { file } from '../preload/file' 6 | import { API } from '../preload/api' 7 | import { RendererLogger, RendererCategoryLogger } from '../preload/logger' 8 | import { ipcClient } from '../preload/ipc-client' 9 | 10 | declare global { 11 | interface Window { 12 | electron: ElectronAPI 13 | api: API 14 | store: ConfigStore 15 | file: typeof file 16 | tools: Tool[] 17 | chatHistory: typeof chatHistory 18 | appWindow: { 19 | isFocused: () => Promise 20 | } 21 | ipc: typeof ipcClient 22 | logger: { 23 | log: RendererLogger 24 | createCategoryLogger: (category: string) => RendererCategoryLogger 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/api/bedrock/types/structured-output.ts: -------------------------------------------------------------------------------- 1 | import { InferenceConfiguration } from '@aws-sdk/client-bedrock-runtime' 2 | 3 | export interface JSONSchema { 4 | type: string 5 | properties?: Record 6 | required?: string[] 7 | items?: any 8 | description?: string 9 | [key: string]: any 10 | } 11 | 12 | export interface StructuredOutputRequest { 13 | modelId: string 14 | systemPrompt: string 15 | userMessage: string 16 | outputSchema: JSONSchema 17 | toolOptions?: { 18 | name?: string 19 | description?: string 20 | } 21 | inferenceConfig?: InferenceConfiguration 22 | } 23 | 24 | export class StructuredOutputError extends Error { 25 | constructor( 26 | message: string, 27 | public code: 'MISSING_OUTPUT' | 'VALIDATION_ERROR' | 'SCHEMA_ERROR', 28 | public details?: Record 29 | ) { 30 | super(message) 31 | this.name = 'StructuredOutputError' 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/TaskCard/TaskErrorDisplay.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { XCircleIcon } from '@heroicons/react/24/outline' 3 | 4 | interface TaskErrorDisplayProps { 5 | error: string 6 | errorTitle: string 7 | } 8 | 9 | export const TaskErrorDisplay: React.FC = ({ error, errorTitle }) => { 10 | return ( 11 |
12 |
13 | 14 |
15 |
{errorTitle}:
16 |
{error}
17 |
18 |
19 |
20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /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/renderer/src/pages/WebsiteGeneratorPage/components/LoaderWithReasoning.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, memo } from 'react' 2 | import { ReasoningTextDisplay } from './ReasoningTextDisplay' 3 | 4 | type LoaderWithReasoningProps = { 5 | children: ReactNode 6 | reasoningText: string 7 | } 8 | 9 | const LoaderWithReasoningComponent = ({ children, reasoningText }: LoaderWithReasoningProps) => { 10 | return ( 11 |
12 | {/* ローダーコンポーネント (WebLoader, RagLoader, etc.) */} 13 | {children} 14 | 15 | {/* ReasoningTextDisplay - 中央に配置 */} 16 |
17 | {reasoningText && } 18 |
19 |
20 | ) 21 | } 22 | 23 | // メモ化してpropsが変更されない限り再レンダリングしない 24 | export const LoaderWithReasoning = memo(LoaderWithReasoningComponent) 25 | LoaderWithReasoning.displayName = 'LoaderWithReasoning' 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.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 | 'no-restricted-syntax': [ 24 | 'warn', 25 | { 26 | selector: 'ImportExpression', 27 | message: 28 | 'Consider using static imports instead of dynamic imports unless specifically required.' 29 | } 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/McpServerSection/types/mcpServer.types.ts: -------------------------------------------------------------------------------- 1 | import { McpServerConfig } from '@/types/agent-chat' 2 | 3 | /** 4 | * 接続テスト結果の型定義 5 | */ 6 | export interface ConnectionTestResult { 7 | success: boolean 8 | message: string 9 | testedAt: number 10 | details?: { 11 | toolCount?: number 12 | toolNames?: string[] 13 | error?: string 14 | errorDetails?: string 15 | startupTime?: number 16 | } 17 | } 18 | 19 | /** 20 | * 接続テスト結果のマップ型 21 | */ 22 | export type ConnectionResultsMap = Record 23 | 24 | /** 25 | * サーバー設定のパース結果 26 | */ 27 | export interface ParsedServerConfig { 28 | success: boolean 29 | servers?: McpServerConfig[] 30 | error?: string 31 | newlyAddedServer?: McpServerConfig 32 | } 33 | 34 | /** 35 | * 接続テスト結果のサマリー 36 | */ 37 | export interface ConnectionSummary { 38 | total: number 39 | success: number 40 | failed: number 41 | notTested: number 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/atoms/AgentIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { CogIcon } from '@heroicons/react/24/outline' 3 | import { getIconByValue } from '@renderer/components/icons/AgentIcons' 4 | import { AgentIcon as AgentIconType } from '@/types/agent-chat' 5 | 6 | interface AgentIconProps { 7 | agent: { icon?: string; iconColor?: string; name: string } | null 8 | size?: 'sm' | 'md' 9 | } 10 | 11 | export const AgentIcon: React.FC = ({ agent, size = 'sm' }) => { 12 | const iconSize = size === 'sm' ? 'h-4 w-4' : 'h-5 w-5' 13 | 14 | if (!agent?.icon) { 15 | return 16 | } 17 | 18 | // 既存のAgentIconsコンポーネントを使用 19 | const iconElement = getIconByValue(agent.icon as AgentIconType, agent.iconColor) 20 | 21 | return ( 22 |
23 | {iconElement} 24 |
25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/LazyVisibleMessage.tsx: -------------------------------------------------------------------------------- 1 | import { useAnimation, motion } from 'framer-motion' 2 | import { useEffect } from 'react' 3 | 4 | type LazyVisibleMessageProps = { 5 | message: string 6 | } 7 | /** 8 | * Lazy visible message component 9 | * @param props 10 | * @constructor 11 | */ 12 | const LazyVisibleMessage = ({ message }: LazyVisibleMessageProps) => { 13 | const controls = useAnimation() 14 | const startAnimation = { opacity: 0, scale: 1 } 15 | const endAnimation = { opacity: 1, scale: 1 } 16 | const transition = { duration: 1 } 17 | 18 | useEffect(() => { 19 | const timer = setTimeout(() => { 20 | controls.start(endAnimation) 21 | }, 3000) 22 | 23 | return () => clearTimeout(timer) 24 | }, [controls]) 25 | 26 | return ( 27 | 28 | {message} 29 | 30 | ) 31 | } 32 | 33 | export default LazyVisibleMessage 34 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | const flowbite = require('flowbite-react/tailwind') 3 | 4 | module.exports = { 5 | content: [ 6 | './src/renderer/src/**/*.{js,jsx,ts,tsx}', 7 | './src/renderer/index.html', 8 | flowbite.content() 9 | ], 10 | theme: { 11 | extend: { 12 | animation: { 13 | 'pulse-slide': 'pulseSlide 1.5s ease-in-out infinite', 14 | 'gradient-x': 'gradient-x 5s ease infinite' 15 | }, 16 | keyframes: { 17 | pulseSlide: { 18 | '0%, 100%': { transform: 'translateX(-100%)' }, 19 | '50%': { transform: 'translateX(200%)' } 20 | }, 21 | 'gradient-x': { 22 | '0%, 100%': { 23 | 'background-position': '0% 50%' 24 | }, 25 | '50%': { 26 | 'background-position': '100% 50%' 27 | } 28 | } 29 | } 30 | } 31 | }, 32 | plugins: [flowbite.plugin()], 33 | darkMode: 'media' 34 | } 35 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | '@common': resolve('src/common') 20 | } 21 | }, 22 | plugins: [ 23 | react(), 24 | svgr({ 25 | svgrOptions: { 26 | exportType: 'default', 27 | ref: true, 28 | svgo: false, 29 | titleProp: true 30 | }, 31 | include: '**/*.svg' 32 | }) 33 | ], 34 | css: { 35 | postcss: { 36 | plugins: [tailwindcss() as any] 37 | } 38 | } 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /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/renderer/src/pages/ChatPage/components/MessageList/Avatar.tsx: -------------------------------------------------------------------------------- 1 | import { ConversationRole } from '@aws-sdk/client-bedrock-runtime' 2 | import React from 'react' 3 | import { LiaUserCircleSolid } from 'react-icons/lia' 4 | import AILogo from '@renderer/assets/images/icons/ai.svg' 5 | 6 | export const Avatar: React.FC<{ role?: ConversationRole }> = ({ role }) => { 7 | const renderAvatar = (role?: ConversationRole) => { 8 | if (role === 'assistant') { 9 | return ( 10 |
11 |
12 | 13 |
14 |
15 | ) 16 | } else { 17 | return ( 18 |
19 | 20 |
21 | ) 22 | } 23 | } 24 | 25 | return ( 26 |
27 | {renderAvatar(role)} 28 |
29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/sections/ConfigDirSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { FcFolder } from 'react-icons/fc' 4 | import { SettingSection } from '../SettingSection' 5 | 6 | interface ProjectSectionProps { 7 | userDataPath: string 8 | } 9 | 10 | export const ConfigDirSection: React.FC = ({ userDataPath }) => { 11 | const { t } = useTranslation() 12 | 13 | return ( 14 | 15 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /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/tools/handlers/todo/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Types for Todo tools 3 | */ 4 | 5 | export type TodoItemStatus = 'pending' | 'in_progress' | 'completed' | 'cancelled' 6 | 7 | export interface TodoItem { 8 | id: string 9 | description: string 10 | status: TodoItemStatus 11 | createdAt: string 12 | updatedAt: string 13 | } 14 | 15 | export interface TodoList { 16 | id: string 17 | items: TodoItem[] 18 | createdAt: string 19 | updatedAt: string 20 | sessionId: string 21 | projectPath: string 22 | } 23 | 24 | export interface TodoItemUpdate { 25 | id: string 26 | status?: TodoItemStatus 27 | description?: string 28 | } 29 | 30 | export interface TodoUpdateResult { 31 | success: boolean 32 | updatedList?: TodoList 33 | currentList?: TodoList 34 | error?: string 35 | } 36 | 37 | /** 38 | * Input types for todo tools 39 | */ 40 | export interface TodoInitInput { 41 | type: 'todoInit' 42 | items: string[] 43 | } 44 | 45 | export interface TodoUpdateInput { 46 | type: 'todoUpdate' 47 | updates: TodoItemUpdate[] 48 | } 49 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/sections/NotificationSection.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next' 2 | import { SettingSection } from '../SettingSection' 3 | import useSetting from '@renderer/hooks/useSetting' 4 | 5 | export const NotificationSection = () => { 6 | const { t } = useTranslation() 7 | const { notification, setNotification } = useSetting() 8 | 9 | return ( 10 | 11 |
12 | setNotification(e.target.checked)} 17 | className="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" 18 | /> 19 | 22 |
23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/components/DomainTag.tsx: -------------------------------------------------------------------------------- 1 | import { FaTimes } from 'react-icons/fa' 2 | 3 | interface DomainTagProps { 4 | domain: string 5 | onRemove: (domain: string) => void 6 | variant?: 'include' | 'exclude' 7 | } 8 | 9 | export const DomainTag = ({ domain, onRemove, variant = 'include' }: DomainTagProps) => { 10 | const bgColor = 11 | variant === 'include' 12 | ? 'bg-blue-100 dark:bg-blue-800 text-blue-800 dark:text-blue-200' 13 | : 'bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-300' 14 | 15 | const hoverColor = 16 | variant === 'include' 17 | ? 'hover:text-blue-600 dark:hover:text-blue-400' 18 | : 'hover:text-gray-500 dark:hover:text-gray-400' 19 | 20 | return ( 21 | 22 | {domain} 23 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/AgentList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { CustomAgent } from '@/types/agent-chat' 3 | import { LoadingSkeleton } from './LoadingSkeleton' 4 | import { EmptyState } from './EmptyState' 5 | import { AgentCard } from './AgentCard' 6 | 7 | interface AgentListProps { 8 | agents: CustomAgent[] 9 | onSelectAgent: (agent: CustomAgent) => void 10 | onTagClick?: (tag: string) => void 11 | isLoading?: boolean 12 | } 13 | 14 | export const AgentList: React.FC = ({ 15 | agents, 16 | onSelectAgent, 17 | onTagClick, 18 | isLoading = false 19 | }) => { 20 | if (isLoading) { 21 | return 22 | } 23 | 24 | if (agents.length === 0) { 25 | return 26 | } 27 | 28 | return ( 29 |
30 | {agents.map((agent) => ( 31 | 32 | ))} 33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/hooks/useAgentTools.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react' 2 | import { useSettings } from '@renderer/contexts/SettingsContext' 3 | import { ToolState } from '@/types/agent-chat' 4 | import { ToolName } from '@/types/tools' 5 | import { READ_ONLY_TOOLS } from '@/types/plan-mode-tools' 6 | 7 | /** 8 | * Custom hook to filter tools based on Plan/Act mode 9 | * @param tools Array of tool states to filter 10 | * @returns Filtered array of tool states based on current mode 11 | */ 12 | export const useAgentTools = (tools: ToolState[]): ToolState[] => { 13 | const { planMode } = useSettings() 14 | 15 | return useMemo(() => { 16 | if (!planMode) { 17 | // In Act mode, return all enabled tools 18 | return tools 19 | } 20 | 21 | // In Plan mode, only return read-only tools 22 | return tools.filter((tool) => { 23 | const toolName = tool.toolSpec?.name as ToolName 24 | const isReadOnly = READ_ONLY_TOOLS.includes(toolName) 25 | 26 | return tool.enabled && isReadOnly 27 | }) 28 | }, [tools, planMode]) 29 | } 30 | -------------------------------------------------------------------------------- /src/renderer/src/hooks/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | /** 4 | * システムのダークモード設定を検出するフック 5 | * @returns isDarkMode: システムがダークモードか 6 | */ 7 | export const useTheme = () => { 8 | // システムのダークモード設定を検出する 9 | const [isDarkMode, setIsDarkMode] = useState(() => { 10 | return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches 11 | }) 12 | 13 | useEffect(() => { 14 | // システムのカラースキームが変更された時に反応 15 | const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') 16 | 17 | const handleChange = (e: MediaQueryListEvent) => { 18 | setIsDarkMode(e.matches) 19 | } 20 | 21 | // 変更イベントのリスナーを追加 22 | if (mediaQuery.addEventListener) { 23 | mediaQuery.addEventListener('change', handleChange) 24 | return () => mediaQuery.removeEventListener('change', handleChange) 25 | } else { 26 | // 古いブラウザ向け(Safari 13未満など) 27 | mediaQuery.addListener(handleChange) 28 | return () => mediaQuery.removeListener(handleChange) 29 | } 30 | }, []) 31 | 32 | return { isDarkMode } 33 | } 34 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/sections/LanguageSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { FcGlobe } from 'react-icons/fc' 4 | import { SettingSection } from '../SettingSection' 5 | import { SettingSelect } from '../SettingSelect' 6 | 7 | interface LanguageSectionProps { 8 | currentLanguage: string 9 | onChangeLanguage: (language: 'ja' | 'en') => void 10 | } 11 | 12 | export const LanguageSection: React.FC = ({ 13 | currentLanguage, 14 | onChangeLanguage 15 | }) => { 16 | const { t } = useTranslation() 17 | 18 | const languageOptions = [ 19 | { value: 'en', label: 'English' }, 20 | { value: 'ja', label: '日本語' } 21 | ] 22 | 23 | return ( 24 | 25 | onChangeLanguage(e.target.value as 'ja' | 'en')} 30 | /> 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/SettingSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { IconType } from 'react-icons' 3 | 4 | interface SettingSectionProps { 5 | title: string 6 | description?: string 7 | icon?: IconType 8 | children: React.ReactNode 9 | } 10 | 11 | export const SettingSection: React.FC = ({ 12 | title, 13 | description, 14 | icon: Icon, 15 | children 16 | }) => { 17 | return ( 18 |
19 |
20 |

21 | {Icon && ( 22 |
23 | 24 | {title} 25 |
26 | )} 27 | {!Icon && title} 28 |

29 | {description && ( 30 |

{description}

31 | )} 32 |
33 |
{children}
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SettingPage/components/sections/ProjectSection.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { FcFolder } from 'react-icons/fc' 4 | import { SettingSection } from '../SettingSection' 5 | 6 | interface ProjectSectionProps { 7 | projectPath: string 8 | onSelectDirectory: () => Promise 9 | } 10 | 11 | export const ProjectSection: React.FC = ({ 12 | projectPath, 13 | onSelectDirectory 14 | }) => { 15 | const { t } = useTranslation() 16 | 17 | return ( 18 | 19 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/iamPolicy.ts: -------------------------------------------------------------------------------- 1 | export const iamPolicy = { 2 | en: { 3 | 'Standard permissions including streaming responses': 4 | 'Standard permissions for APIs used by Bedrock Engineer', 5 | Close: 'Close', 6 | 'Use Recommended Policy for full feature access': 7 | 'Use Recommended Policy for full feature access', 8 | Copy: 'Copy', 9 | 'For more information about IAM policies for Amazon Bedrock, visit the': 10 | 'For more information about IAM policies for Amazon Bedrock, visit the', 11 | 'Amazon Bedrock documentation': 'Amazon Bedrock documentation' 12 | }, 13 | ja: { 14 | 'Standard permissions including streaming responses': 15 | 'Bedrock Engineer で使用している API の標準的なアクセス許可', 16 | Close: '閉じる', 17 | 'Use Recommended Policy for full feature access': 18 | 'すべての機能にアクセスするには推奨ポリシーを使用', 19 | Copy: 'コピー', 20 | 'For more information about IAM policies for Amazon Bedrock, visit the': 21 | 'Amazon Bedrock の IAM ポリシーの詳細については、以下を参照してください。', 22 | 'Amazon Bedrock documentation': 'Amazon Bedrock のドキュメント' 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /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/renderer/src/pages/SpeakPage/constants/voices.ts: -------------------------------------------------------------------------------- 1 | // 音声ID定数 2 | export type VoiceId = 'amy' | 'matthew' | 'tiffany' 3 | 4 | // 音声メタデータの型定義 5 | export interface VoiceMetadata { 6 | id: VoiceId 7 | name: string 8 | description: string 9 | characteristics: string 10 | } 11 | 12 | // 音声選択肢の定義 13 | export const AVAILABLE_VOICES: VoiceMetadata[] = [ 14 | { 15 | id: 'tiffany', 16 | name: 'Tiffany', 17 | description: 'voice.tiffany.description', 18 | characteristics: 'voice.tiffany.characteristics' 19 | }, 20 | { 21 | id: 'amy', 22 | name: 'Amy', 23 | description: 'voice.amy.description', 24 | characteristics: 'voice.amy.characteristics' 25 | }, 26 | { 27 | id: 'matthew', 28 | name: 'Matthew', 29 | description: 'voice.matthew.description', 30 | characteristics: 'voice.matthew.characteristics' 31 | } 32 | ] 33 | 34 | // 音声IDから音声メタデータを取得する関数 35 | export const getVoiceMetadata = (voiceId: VoiceId): VoiceMetadata | undefined => { 36 | return AVAILABLE_VOICES.find((voice) => voice.id === voiceId) 37 | } 38 | 39 | // デフォルト音声ID 40 | export const DEFAULT_VOICE_ID: VoiceId = 'amy' 41 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/utils/eventUtils.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * クリックイベントの伝播を停止する 5 | */ 6 | export const stopPropagation = (e: React.SyntheticEvent): void => { 7 | e.stopPropagation() 8 | } 9 | 10 | /** 11 | * クリックイベントとデフォルト動作を停止する 12 | */ 13 | export const preventEventPropagation = (e: React.SyntheticEvent): void => { 14 | e.preventDefault() 15 | e.stopPropagation() 16 | } 17 | 18 | /** 19 | * マウスダウンとイベント伝播を停止する(ドラッグ防止用) 20 | */ 21 | export const preventMouseDownPropagation = (e: React.MouseEvent): void => { 22 | e.preventDefault() 23 | e.stopPropagation() 24 | } 25 | 26 | /** 27 | * クリックイベント用のラッパー関数を作成 28 | * @param handler 実行するハンドラー関数 29 | * @param preventDefault デフォルト動作を防止するかどうか(デフォルト: false) 30 | */ 31 | export const createClickHandler = void>( 32 | handler: T, 33 | preventDefault: boolean = false 34 | ): ((e: React.MouseEvent) => void) => { 35 | return (e: React.MouseEvent): void => { 36 | e.stopPropagation() 37 | if (preventDefault) { 38 | e.preventDefault() 39 | } 40 | handler(e) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/atoms/ToggleSwitch.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface ToggleSwitchProps { 4 | enabled: boolean 5 | onToggle: (e: React.MouseEvent) => void 6 | disabled?: boolean 7 | enabledLabel?: string 8 | disabledLabel?: string 9 | } 10 | 11 | export const ToggleSwitch: React.FC = ({ 12 | enabled, 13 | onToggle, 14 | disabled = false, 15 | enabledLabel, 16 | disabledLabel 17 | }) => ( 18 | 33 | ) 34 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/planActMode.ts: -------------------------------------------------------------------------------- 1 | export const planActMode = { 2 | en: { 3 | 'Plan mode - Read-only tools enabled': 'Plan mode - Read-only tools enabled', 4 | 'Act mode - All tools enabled': 'Act mode - All tools enabled', 5 | 'Plan mode - Read-only tools enabled (⌘+Shift+A)': 6 | 'Plan mode - Read-only tools enabled (⌘+Shift+A)', 7 | 'Plan mode - Read-only tools enabled (Ctrl+Shift+A)': 8 | 'Plan mode - Read-only tools enabled (Ctrl+Shift+A)', 9 | 'Act mode - All tools enabled (⌘+Shift+A)': 'Act mode - All tools enabled (⌘+Shift+A)', 10 | 'Act mode - All tools enabled (Ctrl+Shift+A)': 'Act mode - All tools enabled (Ctrl+Shift+A)' 11 | }, 12 | ja: { 13 | 'Plan mode - Read-only tools enabled': '読み取り専用ツールのみ有効', 14 | 'Act mode - All tools enabled': 'すべてのツールが有効', 15 | 'Plan mode - Read-only tools enabled (⌘+Shift+A)': '読み取り専用ツールのみ有効 (⌘+Shift+A)', 16 | 'Plan mode - Read-only tools enabled (Ctrl+Shift+A)': 17 | '読み取り専用ツールのみ有効 (Ctrl+Shift+A)', 18 | 'Act mode - All tools enabled (⌘+Shift+A)': 'すべてのツールが有効 (⌘+Shift+A)', 19 | 'Act mode - All tools enabled (Ctrl+Shift+A)': 'すべてのツールが有効 (Ctrl+Shift+A)' 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/renderer/src/hooks/useModal.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import { Modal, ModalSizes } from 'flowbite-react' 3 | import { useState } from 'react' 4 | 5 | type CustomModalProps = { 6 | children: React.ReactNode 7 | header?: React.ReactNode 8 | footer?: React.ReactNode 9 | size?: keyof ModalSizes 10 | } 11 | 12 | /** 13 | * @deprecated use flowbite-react Modal instead 14 | * @returns 15 | */ 16 | const useModal = () => { 17 | const [show, setShow] = useState(false) 18 | 19 | const openModal = () => { 20 | setShow(true) 21 | } 22 | 23 | const closeModal = () => { 24 | setShow(false) 25 | } 26 | 27 | const CustomModal: React.FC = ({ children, header, footer, size }) => ( 28 | <> 29 | setShow(false)} size={size}> 30 | {header && {header}} 31 | {children} 32 | {footer && {footer}} 33 | 34 | 35 | ) 36 | 37 | return { 38 | Modal: CustomModal, 39 | openModal, 40 | closeModal 41 | } 42 | } 43 | 44 | export default useModal 45 | -------------------------------------------------------------------------------- /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/renderer/src/pages/AgentDirectoryPage/components/AgentDetailModal/useAgentDetailModal.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | 3 | interface UseAgentDetailModalProps { 4 | onAddToMyAgents?: () => void 5 | onClose: () => void 6 | } 7 | 8 | export const useAgentDetailModal = ({ onAddToMyAgents, onClose }: UseAgentDetailModalProps) => { 9 | const [isAdding, setIsAdding] = useState(false) 10 | const [addSuccess, setAddSuccess] = useState(null) 11 | 12 | const handleAddToMyAgents = async () => { 13 | if (onAddToMyAgents) { 14 | setIsAdding(true) 15 | try { 16 | onAddToMyAgents() 17 | setAddSuccess(true) 18 | setTimeout(() => { 19 | onClose() 20 | }, 2000) 21 | } catch (error) { 22 | setAddSuccess(false) 23 | console.error('Error adding agent:', error) 24 | } finally { 25 | setIsAdding(false) 26 | } 27 | } 28 | } 29 | 30 | // Reset state when modal closes 31 | useEffect(() => { 32 | return () => { 33 | setAddSuccess(null) 34 | setIsAdding(false) 35 | } 36 | }, []) 37 | 38 | return { 39 | isAdding, 40 | addSuccess, 41 | handleAddToMyAgents 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/AgentDetailModal/components/ScenariosList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { Scenario } from '@/types/agent-chat' 4 | 5 | interface ScenariosListProps { 6 | scenarios: Scenario[] 7 | } 8 | 9 | export const ScenariosList: React.FC = ({ scenarios }) => { 10 | const { t } = useTranslation() 11 | 12 | if (!scenarios || scenarios.length === 0) { 13 | return null 14 | } 15 | 16 | return ( 17 |
18 |

{t('scenariosLabel')}

19 |
20 | {scenarios.map((scenario, index) => ( 21 |
25 |

{scenario.title}

26 |
27 | {scenario.content} 28 |
29 |
30 | ))} 31 |
32 |
33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/McpServerSection/utils/connectionTestUtils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ConnectionResultsMap, 3 | ConnectionSummary, 4 | ConnectionTestResult 5 | } from '../types/mcpServer.types' 6 | 7 | /** 8 | * 接続テスト結果のサマリーを生成する 9 | * @param results 接続テスト結果のオブジェクト 10 | * @param totalServers 全サーバー数 11 | * @returns {ConnectionSummary} テスト結果のサマリー 12 | */ 13 | export function generateConnectionSummary( 14 | results: ConnectionResultsMap, 15 | totalServers: number 16 | ): ConnectionSummary { 17 | const testedServers = Object.keys(results).length 18 | const successServers = Object.values(results).filter((r) => r.success).length 19 | 20 | return { 21 | total: totalServers, 22 | success: successServers, 23 | failed: testedServers - successServers, 24 | notTested: totalServers - testedServers 25 | } 26 | } 27 | 28 | /** 29 | * 接続テスト結果を整形する 30 | * @param result APIから返された生の結果 31 | * @returns {ConnectionTestResult} 整形された結果オブジェクト 32 | */ 33 | export function formatConnectionResult(result: any): ConnectionTestResult { 34 | return { 35 | success: result.success, 36 | message: result.message, 37 | testedAt: Date.now(), 38 | details: result.details || {} 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/api/bedrock/services/modelService.ts: -------------------------------------------------------------------------------- 1 | import { getDefaultPromptRouter, getModelsForRegion } from '../../../../common/models/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/renderer/src/pages/ChatPage/components/CodeBlocks/ApplyDiffEdit/ApplyDiffEditResult.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { DiffViewer } from './DiffViewer' 4 | import { ApplyDiffEditResultProps } from './types' 5 | 6 | export const ApplyDiffEditResult: React.FC = ({ response }) => { 7 | const { t } = useTranslation() 8 | 9 | // If there was an error 10 | if (!response.success) { 11 | return ( 12 |
13 |

{t('errors.failedToApplyChanges')}

14 |

{response.error}

15 |
16 | ) 17 | } 18 | 19 | // If there's no result data 20 | if (!response.result) { 21 | return ( 22 |
23 |

{t('common.noResults')}

24 |
25 | ) 26 | } 27 | 28 | return ( 29 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/components/Preview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { SandpackPreview } from '@codesandbox/sandpack-react' 3 | import { FiMaximize } from 'react-icons/fi' 4 | 5 | interface PreviewProps { 6 | isDark: boolean 7 | code: string 8 | } 9 | 10 | export const Preview: React.FC = ({ isDark, code }) => { 11 | return ( 12 | { 28 | const iframe = document.getElementById('sandpack-preview') 29 | if (iframe) { 30 | iframe?.requestFullscreen() 31 | } 32 | }} 33 | className="border rounded-full bg-[#EFEFEF] p-2 text-gray-500 hover:text-gray-800" 34 | > 35 | 36 | 37 | } 38 | /> 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/types/chat/history.ts: -------------------------------------------------------------------------------- 1 | import { ConversationRole, ContentBlock } from '@aws-sdk/client-bedrock-runtime' 2 | import { ToolState } from '../agent-chat' 3 | 4 | type AttachedImage = { 5 | file: File 6 | preview: string 7 | base64: string 8 | } 9 | 10 | export interface ChatMessage { 11 | id: string 12 | role: ConversationRole 13 | content: ContentBlock[] 14 | timestamp: number 15 | metadata?: { 16 | modelId?: string 17 | tools?: ToolState[] 18 | images?: AttachedImage[] 19 | converseMetadata?: Record // BedrockのConverseStreamMetadataEvent型のデータを保存するフィールド 20 | } 21 | } 22 | 23 | export interface SessionMetadata { 24 | id: string 25 | title: string 26 | createdAt: number 27 | updatedAt: number 28 | messageCount: number 29 | agentId: string 30 | modelId: string 31 | systemPrompt?: string 32 | } 33 | 34 | export interface ChatSession { 35 | id: string 36 | title: string 37 | createdAt: number 38 | updatedAt: number 39 | messages: ChatMessage[] 40 | agentId: string 41 | systemPrompt?: string 42 | modelId: string 43 | } 44 | 45 | export interface ChatHistoryStore { 46 | sessions: { 47 | [key: string]: ChatSession 48 | } 49 | activeSessionId?: string 50 | recentSessions: string[] // 最近使用したセッションID(最大10個) 51 | } 52 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/stepFunctionGenerator/index.ts: -------------------------------------------------------------------------------- 1 | export const stepFunctionGenerator = { 2 | en: { 3 | // Step Function Generator related translations 4 | implementWithCDK: 'Implement with AWS CDK', 5 | continueWithCDK: 'Continue with CDK implementation', 6 | cdkImplementation: 'CDK Implementation', 7 | stateMachineDefinition: 'State Machine Definition', 8 | implementingCDK: 'Implementing with CDK...', 9 | generateStateMachine: 'Generate State Machine', 10 | stateMachinePreview: 'State Machine Preview', 11 | stateMachineEditor: 'State Machine Editor', 12 | implementDescription: 'Implement this state machine with AWS CDK', 13 | uploadingDefinition: 'Uploading state machine definition to agent chat...' 14 | }, 15 | ja: { 16 | // Step Function Generator related translations 17 | implementWithCDK: 'AWS CDKで実装する', 18 | continueWithCDK: 'CDKでステートマシンを実装します', 19 | cdkImplementation: 'CDK実装', 20 | stateMachineDefinition: 'ステートマシン定義', 21 | implementingCDK: 'CDKで実装中...', 22 | generateStateMachine: 'ステートマシンを生成', 23 | stateMachinePreview: 'ステートマシンプレビュー', 24 | stateMachineEditor: 'ステートマシンエディタ', 25 | implementDescription: 'このステートマシンをAWS CDKで実装する', 26 | uploadingDefinition: 'ステートマシン定義をエージェントチャットにアップロード中...' 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/components/AvailableToolsTab/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { ToolCategorySection } from './ToolCategorySection' 4 | import { AvailableToolsTabProps } from '../../types' 5 | import { preventEventPropagation } from '../../utils/eventUtils' 6 | 7 | /** 8 | * 利用可能なツールタブコンポーネント 9 | */ 10 | export const AvailableToolsTab: React.FC = ({ 11 | categorizedTools, 12 | mcpServers, 13 | onToggleTool, 14 | onShowToolInfo, 15 | isLoadingMcpTools = false 16 | }) => { 17 | const { t } = useTranslation() 18 | 19 | return ( 20 |
21 |

{t('tools.description')}

22 | 23 | {/* ツールカテゴリセクションをループで表示 */} 24 | {categorizedTools.map((category) => ( 25 | 33 | ))} 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/main/mcp/command-resolver.ts: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'fs' 2 | import { join } from 'path' 3 | 4 | /** 5 | * コマンドのパスを解決する関数 6 | * ローカルの実行可能ファイルを優先的に検索し、見つからない場合はシステムPATHに依存する 7 | */ 8 | export function resolveCommand(command: string): string { 9 | // 既に絶対パスまたは相対パスの場合はそのまま返す 10 | if (command.includes('/') || command.includes('\\')) { 11 | return command 12 | } 13 | 14 | // よく使われるコマンドの一般的なパスを確認 15 | const commonPaths = [ 16 | // Node.js系 17 | join(process.cwd(), 'node_modules', '.bin', command), 18 | join(process.cwd(), 'node_modules', '.bin', `${command}.cmd`), // Windows 19 | join(process.cwd(), 'node_modules', '.bin', `${command}.ps1`), // PowerShell 20 | 21 | // システム系 22 | `/usr/local/bin/${command}`, 23 | `/opt/homebrew/bin/${command}`, // Apple Silicon Mac 24 | `/usr/bin/${command}`, 25 | `/bin/${command}`, 26 | 27 | // Python/pipx系 28 | join(process.env.HOME || '', '.local', 'bin', command), 29 | 30 | // Windows系 31 | `C:\\Program Files\\nodejs\\${command}.exe`, 32 | `C:\\Windows\\System32\\${command}.exe` 33 | ] 34 | 35 | // 存在する最初のパスを返す 36 | for (const path of commonPaths) { 37 | if (existsSync(path)) { 38 | return path 39 | } 40 | } 41 | 42 | // 見つからない場合は元のコマンド名をそのまま返す(システムPATHに依存) 43 | return command 44 | } 45 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/extensions/preserveScrollPosition.ts: -------------------------------------------------------------------------------- 1 | import { EditorView } from '@codemirror/view' 2 | import { Extension } from '@codemirror/state' 3 | 4 | /** 5 | * CodeMirror extension to preserve scroll position during code updates 6 | * 7 | * This extension tracks the user's scroll position and restores it after 8 | * document changes, allowing users to freely scroll while code is being 9 | * generated in real-time. 10 | * 11 | * @returns CodeMirror Extension 12 | */ 13 | export const preserveScrollPosition = (): Extension => { 14 | let scrollPos: { top: number; left: number } | null = null 15 | 16 | return [ 17 | EditorView.domEventHandlers({ 18 | scroll(_event, view) { 19 | // ユーザーのスクロール操作を記録 20 | scrollPos = { 21 | top: view.scrollDOM.scrollTop, 22 | left: view.scrollDOM.scrollLeft 23 | } 24 | return false 25 | } 26 | }), 27 | EditorView.updateListener.of((update) => { 28 | if (update.docChanged && scrollPos) { 29 | // ドキュメント変更時にスクロール位置を復元 30 | requestAnimationFrame(() => { 31 | if (scrollPos) { 32 | update.view.scrollDOM.scrollTop = scrollPos.top 33 | update.view.scrollDOM.scrollLeft = scrollPos.left 34 | } 35 | }) 36 | } 37 | }) 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /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/test/src/preload/tools.test.ts: -------------------------------------------------------------------------------- 1 | import { expect, test } from '@jest/globals' 2 | import * as fs from 'fs/promises' 3 | import { applyPatch } from 'diff' 4 | 5 | export async function applyPatchToFile(filePath: string, patch: string): Promise { 6 | try { 7 | // ファイルの内容を読み込む 8 | const originalContent = await fs.readFile(filePath, 'utf-8') 9 | 10 | // パッチを適用 11 | const patchedContent = applyPatch(originalContent, patch, { fuzzFactor: 2 }) 12 | console.log(patchedContent) 13 | if (typeof patchedContent === 'string') { 14 | // 変更された内容をファイルに書き込む 15 | await fs.writeFile(filePath, patchedContent, 'utf-8') 16 | return `Successfully applied patch to ${filePath}` 17 | } else { 18 | throw new Error(`Failed to apply patch. ${JSON.stringify(patchedContent)}`) 19 | } 20 | } catch (e: any) { 21 | console.log(e) 22 | return `Error applying patch to ${filePath}: ${e.message}` 23 | } 24 | } 25 | 26 | test.skip('applyPatchToFile', async () => { 27 | const patch = `--- a/greeting.ts 28 | +++ b/greeting.ts 29 | @@ -1,3 +1,3 @@ 30 | function greeting(name: string) { 31 | - console.log("Hello, " + name); 32 | + console.log("Hello, " + n); 33 | } 34 | ` 35 | 36 | const res = await applyPatchToFile('/Users/geeawa/work/electron/bedrock-engineer/aaa.js', patch) 37 | console.log(res) 38 | expect(1).toBe(1) 39 | }) 40 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/AgentDetailModal/components/AgentHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TbRobot } from 'react-icons/tb' 3 | import { AgentIcon } from '@/types/agent-chat' 4 | import { getIconByValue } from '@renderer/components/icons/AgentIcons' 5 | 6 | interface AgentHeaderProps { 7 | name: string 8 | description?: string 9 | icon?: AgentIcon 10 | iconColor?: string 11 | } 12 | 13 | export const AgentHeader: React.FC = ({ name, description, icon, iconColor }) => { 14 | const defaultColor = '#3B82F6' 15 | 16 | return ( 17 |
18 |
19 | {icon ? ( 20 | getIconByValue(icon, iconColor || defaultColor) || ( 21 | 22 | ) 23 | ) : ( 24 | 25 | 👤 26 | 27 | )} 28 |
29 |
30 |

{name}

31 | {description &&

{description}

} 32 |
33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/atoms/StatusBadge.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { XCircleIcon } from '@heroicons/react/24/outline' 3 | 4 | interface StatusBadgeProps { 5 | type: 'error' | 'success' | 'warning' | 'info' 6 | children: React.ReactNode 7 | icon?: React.ReactNode 8 | } 9 | 10 | export const StatusBadge: React.FC = ({ type, children, icon }) => { 11 | const getTypeClasses = () => { 12 | switch (type) { 13 | case 'error': 14 | return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' 15 | case 'success': 16 | return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' 17 | case 'warning': 18 | return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200' 19 | case 'info': 20 | return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200' 21 | default: 22 | return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-200' 23 | } 24 | } 25 | 26 | const defaultIcon = type === 'error' ? : null 27 | 28 | return ( 29 | 32 | {icon || defaultIcon} 33 | {children} 34 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /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/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/pages/SettingPage/types/index.ts: -------------------------------------------------------------------------------- 1 | export interface SettingFormData { 2 | // Project Settings 3 | projectPath: string 4 | 5 | // Language Settings 6 | language: string 7 | 8 | // Agent Chat Settings 9 | tavilySearchApiKey: string 10 | 11 | // AWS Settings 12 | awsRegion: string 13 | awsAccessKeyId: string 14 | awsSecretAccessKey: string 15 | 16 | // Bedrock Settings 17 | llmModelId: string 18 | inferenceParams: { 19 | maxTokens: number 20 | temperature: number 21 | topP: number 22 | } 23 | bedrockSettings: { 24 | enableRegionFailover: boolean 25 | availableRegions: string[] 26 | } 27 | onUpdateBedrockSettings: ( 28 | settings: Partial<{ 29 | enableRegionFailover: boolean 30 | availableRegions: string[] 31 | }> 32 | ) => void 33 | 34 | // Advanced Settings 35 | sendMsgKey: 'Enter' | 'Cmd+Enter' 36 | 37 | // Notification Settings 38 | enableNotification?: boolean 39 | } 40 | 41 | export interface SettingFormErrors { 42 | awsAccessKeyId?: string 43 | awsSecretAccessKey?: string 44 | tavilySearchApiKey?: string 45 | inferenceParams?: { 46 | maxTokens?: string 47 | temperature?: string 48 | topP?: string 49 | } 50 | } 51 | 52 | export interface SettingSectionProps { 53 | className?: string 54 | children: React.ReactNode 55 | title: string 56 | description?: string 57 | } 58 | -------------------------------------------------------------------------------- /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 ProxyConfiguration = { 20 | enabled: boolean 21 | host?: string 22 | port?: number 23 | username?: string 24 | password?: string 25 | protocol?: 'http' | 'https' 26 | } 27 | 28 | export type ProxySettings = { 29 | proxyConfig?: ProxyConfiguration 30 | } 31 | 32 | export type AWSCredentials = { 33 | accessKeyId: string 34 | secretAccessKey: string 35 | sessionToken?: string 36 | region: string 37 | profile?: string 38 | useProfile?: boolean 39 | proxyConfig?: ProxyConfiguration 40 | } 41 | 42 | export interface ThinkingMode { 43 | type: 'enabled' | 'disabled' 44 | budget_tokens?: number 45 | } 46 | 47 | export type InferenceParams = { 48 | maxTokens: number 49 | temperature: number 50 | topP?: number 51 | thinking?: ThinkingMode 52 | } 53 | 54 | export type ServiceContext = { 55 | store: ConfigStore 56 | } 57 | -------------------------------------------------------------------------------- /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/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/renderer/src/i18n/locales/websiteGenerator/index.ts: -------------------------------------------------------------------------------- 1 | export const websiteGenerator = { 2 | en: { 3 | // Website generator related translations 4 | continueInAgentChat: 'Continue development in Agent Chat', 5 | continueDescription: 'Continue implementing and enhancing this website with an agent', 6 | continueDevelopment: 'Continue Development', 7 | websiteCode: 'Website Code', 8 | implementingWebsite: 'Implementing website...', 9 | codeGeneration: 'Code generation', 10 | websitePreview: 'Website Preview', 11 | generatedCode: 'Generated Code', 12 | continuePrompt: 'What would you like to improve or add?', 13 | websiteTemplate: 'Template', 14 | styleType: 'Style', 15 | websiteDescription: 'Description', 16 | uploadingCode: 'Uploading code to agent chat...' 17 | }, 18 | ja: { 19 | // Website generator related translations 20 | continueInAgentChat: 'Agent Chatで開発を続ける', 21 | continueDescription: 'エージェントでこのウェブサイトの実装・改善を続けましょう', 22 | continueDevelopment: '開発を続ける', 23 | websiteCode: 'ウェブサイトコード', 24 | implementingWebsite: 'ウェブサイトを実装中...', 25 | codeGeneration: 'コード生成', 26 | websitePreview: 'ウェブサイトプレビュー', 27 | generatedCode: '生成されたコード', 28 | continuePrompt: '何を改善または追加しますか?', 29 | websiteTemplate: 'テンプレート', 30 | styleType: 'スタイル', 31 | websiteDescription: '説明', 32 | uploadingCode: 'コードをエージェントチャットにアップロード中...' 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/notification.ts: -------------------------------------------------------------------------------- 1 | export const notificationSettings = { 2 | en: { 3 | notification: { 4 | title: 'Notification Settings', 5 | description: 'Configure desktop notifications for chat responses', 6 | enable: 'Enable desktop notifications', 7 | messages: { 8 | chatComplete: { 9 | title: 'Task Complete 🎉', 10 | body: 'AI response has arrived' 11 | }, 12 | backgroundAgentSuccess: { 13 | title: 'Background Task Complete ✅', 14 | body: 'Background agent task completed successfully' 15 | }, 16 | backgroundAgentError: { 17 | title: 'Background Task Failed ❌', 18 | body: 'Background agent task failed to execute' 19 | } 20 | } 21 | } 22 | }, 23 | ja: { 24 | notification: { 25 | title: '通知設定', 26 | description: 'チャットの応答に関するデスクトップ通知を設定します', 27 | enable: 'デスクトップ通知を有効にする', 28 | messages: { 29 | chatComplete: { 30 | title: 'タスクが完了しました 🎉', 31 | body: 'AIからの返信が届きました' 32 | }, 33 | backgroundAgentSuccess: { 34 | title: 'バックグラウンドタスク完了 ✅', 35 | body: 'バックグラウンドエージェントタスクが正常に完了しました' 36 | }, 37 | backgroundAgentError: { 38 | title: 'バックグラウンドタスクエラー ❌', 39 | body: 'バックグラウンドエージェントタスクの実行に失敗しました' 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/TaskListView.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ScheduledTask, ScheduleConfig } from '../../hooks/useBackgroundAgent' 3 | import { TaskCard } from './TaskCard' 4 | 5 | interface TaskListViewProps { 6 | tasks: ScheduledTask[] 7 | taskLoadingStates: { [taskId: string]: boolean } 8 | onToggleTask: (taskId: string, enabled: boolean) => Promise 9 | onCancelTask: (taskId: string) => Promise 10 | onExecuteTask: (taskId: string) => Promise 11 | onUpdateTask: (taskId: string, config: ScheduleConfig) => Promise 12 | onGetTaskSystemPrompt: (taskId: string) => Promise 13 | } 14 | 15 | export const TaskListView: React.FC = ({ 16 | tasks, 17 | taskLoadingStates, 18 | onToggleTask, 19 | onCancelTask, 20 | onExecuteTask, 21 | onUpdateTask, 22 | onGetTaskSystemPrompt 23 | }) => { 24 | return ( 25 |
26 | {tasks.map((task) => ( 27 | 37 | ))} 38 |
39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/main/handlers/proxy-handlers.ts: -------------------------------------------------------------------------------- 1 | import { testProxyConnection } from '../lib/proxy-utils' 2 | import { updateProxySettings } from '../index' 3 | import { log } from '../../common/logger' 4 | import type { ProxyConfiguration } from '../api/bedrock/types' 5 | 6 | /** 7 | * プロキシ関連のIPCハンドラー定義 8 | */ 9 | export const proxyHandlers = { 10 | // プロキシ接続テスト 11 | 'proxy:test-connection': async (_, proxyConfig: ProxyConfiguration) => { 12 | try { 13 | log.info('Testing proxy connection', { host: proxyConfig.host, port: proxyConfig.port }) 14 | const result = await testProxyConnection(proxyConfig) 15 | return { success: true, connected: result } 16 | } catch (error) { 17 | log.error('Proxy connection test failed', { 18 | error: error instanceof Error ? error.message : String(error) 19 | }) 20 | return { success: false, error: error instanceof Error ? error.message : String(error) } 21 | } 22 | }, 23 | 24 | // プロキシ設定更新(動的適用) 25 | 'proxy:update-settings': async () => { 26 | try { 27 | log.info('Updating proxy settings') 28 | await updateProxySettings() 29 | return { success: true } 30 | } catch (error) { 31 | log.error('Proxy settings update failed', { 32 | error: error instanceof Error ? error.message : String(error) 33 | }) 34 | return { success: false, error: error instanceof Error ? error.message : String(error) } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/InputForm/DirectorySelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { FcFolder } from 'react-icons/fc' 3 | 4 | type DirectorySelectorProps = { 5 | projectPath: string 6 | onSelectDirectory: () => void 7 | onOpenIgnoreModal: () => void 8 | } 9 | 10 | export const DirectorySelector: React.FC = ({ 11 | projectPath, 12 | onSelectDirectory, 13 | onOpenIgnoreModal 14 | }) => { 15 | // プロジェクトパスが有効に選択されているかを判定 16 | const isProjectSelected = 17 | projectPath && 18 | projectPath.trim() !== '' && 19 | !projectPath.includes('選択') && 20 | !projectPath.includes('Select') && 21 | (projectPath.startsWith('/') || projectPath.match(/^[A-Za-z]:/)) 22 | 23 | return ( 24 |
25 | 34 | {isProjectSelected && ( 35 | 41 | )} 42 |
43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/Recommendations/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { motion } from 'framer-motion' 3 | import LoadingDotsLottie from '../../../WebsiteGeneratorPage/LoadingDots.lottie' 4 | 5 | type MessageRecommendation = { 6 | title: string 7 | content: string 8 | } 9 | 10 | type RecommendationsProps = { 11 | recommendations: MessageRecommendation[] 12 | loading: boolean 13 | onSelect: (content: string) => void 14 | } 15 | 16 | export const Recommendations: React.FC = ({ 17 | recommendations, 18 | loading, 19 | onSelect 20 | }) => { 21 | if (loading) { 22 | return ( 23 |
24 | 25 |
26 | ) 27 | } 28 | 29 | return ( 30 |
31 | {recommendations.map((recommendation, index) => ( 32 | onSelect(recommendation.content)} 39 | > 40 | {recommendation.title} 41 | 42 | ))} 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/CodeBlocks/TavilySearch/SearchResult.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface Props { 4 | result: { 5 | title: string 6 | url: string 7 | content: string 8 | score: number 9 | } 10 | } 11 | 12 | export const SearchResult: React.FC = ({ result }) => { 13 | const { title, url, content, score } = result 14 | 15 | const handleUrlClick = (url: string) => { 16 | open(url) 17 | } 18 | 19 | return ( 20 |
21 | {/* Title & Score */} 22 |
23 |

24 | {title} 25 |

26 | 27 | {(score * 100).toFixed(1)}% 28 | 29 |
30 | 31 | {/* URL */} 32 |
handleUrlClick(url)} 35 | > 36 | {url} 37 |
38 | 39 | {/* Content */} 40 |

{content}

41 |
42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/components/TemplateButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { SupportedTemplate } from '../templates' 3 | import { sleep } from '@renderer/lib/util' 4 | 5 | interface TemplateButtonProps extends SupportedTemplate { 6 | isSelected: boolean 7 | onSelect: (id: SupportedTemplate['id']) => void 8 | onRefresh: () => void 9 | } 10 | 11 | export const TemplateButton: React.FC = ({ 12 | id, 13 | name, 14 | logo, 15 | isSelected, 16 | onSelect, 17 | onRefresh 18 | }) => { 19 | return ( 20 | 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /src/renderer/src/pages/StepFunctionsGeneratorPage/ASLEditor.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | /* eslint-disable @typescript-eslint/no-unused-vars */ 3 | import { Editor } from '@monaco-editor/react' 4 | import { useRef } from 'react' 5 | 6 | type ASLEditorProps = { value: any; setValue?: any } 7 | export const ASLEditor: React.FC = ({ value, setValue }) => { 8 | const editorRef = useRef(null) 9 | 10 | function handleEditorChange(value: any, _event: any) { 11 | // here is the current value 12 | setValue(value) 13 | } 14 | 15 | function handleEditorDidMount(editor: any, _monaco: any) { 16 | editorRef.current = editor 17 | } 18 | 19 | function handleEditorWillMount(_monaco: any) { 20 | // console.log("beforeMount: the monaco instance:", monaco); 21 | } 22 | 23 | function handleEditorValidation(_markers: any) { 24 | // model markers 25 | // markers.forEach(marker => console.log('onValidate:', marker.message)); 26 | } 27 | 28 | const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches 29 | return ( 30 | <> 31 | 42 | 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/AgentDetailModal/components/ToolsList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { ToolName, isMcpTool } from '@/types/tools' 4 | import { toolIcons } from '@renderer/components/icons/ToolIcons' 5 | 6 | interface ToolsListProps { 7 | tools: string[] 8 | } 9 | 10 | export const ToolsList: React.FC = ({ tools }) => { 11 | const { t } = useTranslation() 12 | 13 | if (!tools || tools.length === 0) { 14 | return null 15 | } 16 | 17 | // MCPツールを除外 18 | const standardTools = tools.filter((tool) => !isMcpTool(tool)) 19 | 20 | if (standardTools.length === 0) { 21 | return null 22 | } 23 | 24 | return ( 25 |
26 |

{t('toolsLabel')}

27 |
28 |
29 | {standardTools.map((tool) => ( 30 | 34 | {toolIcons[tool as ToolName]} 35 | {tool} 36 | 37 | ))} 38 |
39 |
40 |
41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/src/pages/DiagramGeneratorPage/components/LoaderWithReasoning.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, memo } from 'react' 2 | import { ReasoningTextDisplay } from './ReasoningTextDisplay' 3 | import { ProgressBar } from './ProgressBar' 4 | 5 | type LoaderWithReasoningProps = { 6 | children: ReactNode 7 | reasoningText: string 8 | progress?: number 9 | progressMessage?: string 10 | showProgress?: boolean 11 | } 12 | 13 | const LoaderWithReasoningComponent = ({ 14 | children, 15 | reasoningText, 16 | progress, 17 | progressMessage, 18 | showProgress = false 19 | }: LoaderWithReasoningProps) => { 20 | return ( 21 |
22 | {/* ローダーコンポーネント (WebLoader, RagLoader, etc.) */} 23 | {children} 24 | 25 | {/* 進捗バー表示 */} 26 | {showProgress && progress !== undefined && ( 27 |
28 | 34 |
35 | )} 36 | 37 | {/* ReasoningTextDisplay - 中央に配置 */} 38 |
39 | {reasoningText && } 40 |
41 |
42 | ) 43 | } 44 | 45 | // メモ化してpropsが変更されない限り再レンダリングしない 46 | export const LoaderWithReasoning = memo(LoaderWithReasoningComponent) 47 | LoaderWithReasoning.displayName = 'LoaderWithReasoning' 48 | -------------------------------------------------------------------------------- /src/renderer/src/components/LocalImage/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | 3 | interface LocalImageProps { 4 | src: string 5 | alt: string 6 | className?: string 7 | } 8 | 9 | const LocalImage: React.FC = ({ src, alt, className }) => { 10 | const [imageUrl, setImageUrl] = useState('') 11 | const [error, setError] = useState('') 12 | const [loading, setLoading] = useState(true) 13 | 14 | useEffect(() => { 15 | const loadImage = async () => { 16 | try { 17 | setLoading(true) 18 | const dataUrl = await window.api.images.getLocalImage(src) 19 | setImageUrl(dataUrl) 20 | setError('') 21 | } catch (err) { 22 | setError('Failed to load image') 23 | console.error('Error loading image:', err) 24 | } finally { 25 | setLoading(false) 26 | } 27 | } 28 | 29 | if (src) { 30 | loadImage() 31 | } 32 | }, [src]) 33 | 34 | if (loading) { 35 | return
36 | } 37 | 38 | if (error) { 39 | return ( 40 |
41 | {error} 42 |
43 | ) 44 | } 45 | 46 | return ( 47 | {alt} 53 | ) 54 | } 55 | 56 | export default LocalImage 57 | -------------------------------------------------------------------------------- /src/main/api/bedrock/utils/toolGenerator.ts: -------------------------------------------------------------------------------- 1 | import { Tool } from '@aws-sdk/client-bedrock-runtime' 2 | import { JSONSchema } from '../types/structured-output' 3 | 4 | /** 5 | * Utility class to generate Bedrock Tool definitions from JSON schemas 6 | */ 7 | export class ToolGenerator { 8 | /** 9 | * Generate a Bedrock Tool definition from a JSON schema 10 | * @param schema - The JSON schema defining the expected output structure 11 | * @param options - Optional tool metadata 12 | * @returns A Bedrock Tool definition 13 | */ 14 | static generateFromSchema( 15 | schema: JSONSchema, 16 | options?: { 17 | name?: string 18 | description?: string 19 | } 20 | ): Tool { 21 | return { 22 | toolSpec: { 23 | name: options?.name || 'structured_output', 24 | description: 25 | options?.description || 'Return structured data according to the specified schema', 26 | inputSchema: { 27 | json: schema 28 | } 29 | } 30 | } 31 | } 32 | 33 | /** 34 | * Wrap a schema in an object with a single property 35 | * Useful for adding a top-level wrapper around the schema 36 | * @param schema - The schema to wrap 37 | * @param wrapperKey - The key to use for wrapping (default: 'output') 38 | * @returns A wrapped schema 39 | */ 40 | static wrapSchema(schema: JSONSchema, wrapperKey = 'output'): JSONSchema { 41 | return { 42 | type: 'object', 43 | properties: { 44 | [wrapperKey]: schema 45 | }, 46 | required: [wrapperKey] 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/renderer/src/i18n/locales/settings/agentSettings.ts: -------------------------------------------------------------------------------- 1 | export const agentSettings = { 2 | en: { 3 | 'agentSettings.infoTitle': 'How to use custom agents and shared agents', 4 | 'agentSettings.description': 5 | 'Create and customize AI agents to assist with specific tasks. You can edit existing agents or create new ones with customized system prompts, capabilities, and appearance.', 6 | 'agentSettings.sharedAgentsDescription': 7 | 'To share agents across projects, use the "Save as Shared File" option. Shared agents can be stored in your project directories and will be automatically loaded when you open that project. Shared agent configuration files are stored under .bedrock-engineer/agents/.', 8 | 'Basic Agent Settings': 'Basic Agent Settings', 9 | generateVoiceChatPrompt: 'Voice Chat', 10 | generateVoiceChatPromptTooltip: 11 | 'Generate a system prompt optimized for voice-based conversations (Nova Sonic)' 12 | }, 13 | ja: { 14 | 'agentSettings.infoTitle': 'カスタムエージェントと共有エージェントの使い方', 15 | 'agentSettings.description': 16 | 'AIエージェントを作成・カスタマイズして、特定のタスクをサポートできます。既存のエージェントを編集したり、カスタマイズされたシステムプロンプト、機能を持つ新しいエージェントを作成したりできます。', 17 | 'agentSettings.sharedAgentsDescription': 18 | 'プロジェクト間でエージェントを共有するには、「共有ファイルとして保存」オプションを使用します。共有エージェントはプロジェクトディレクトリに保存でき、そのプロジェクトを開くと自動的に読み込まれます。共有エージェントの設定ファイルは .bedrock-engineer/agents/ に保存されます。', 19 | 'Basic Agent Settings': '基本設定', 20 | generateVoiceChatPrompt: '音声チャットに最適に生成する', 21 | generateVoiceChatPromptTooltip: 22 | '音声ベースの会話に最適化したシステムプロンプトを生成(Nova Sonic)' 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/common/mcp/schemas.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'zod' 2 | 3 | /** 4 | * MCPサーバー設定のZodスキーマ 5 | * preloadとrendererの両方で使用される共通スキーマ 6 | */ 7 | export const mcpServerConfigSchema = z.object({ 8 | mcpServers: z.record( 9 | z.string(), 10 | z.union([ 11 | // コマンド形式のサーバー設定 12 | z.object({ 13 | command: z.string(), 14 | args: z.array(z.string()), 15 | env: z.record(z.string(), z.string()).optional() 16 | }), 17 | // URL形式のサーバー設定 18 | z.object({ 19 | url: z.string(), 20 | enabled: z.boolean().optional(), 21 | headers: z.record(z.string(), z.string()).optional() 22 | }) 23 | ]) 24 | ) 25 | }) 26 | 27 | /** 28 | * Zodエラーをユーザーフレンドリーなメッセージに変換 29 | */ 30 | export function formatZodError(error: z.ZodError): string { 31 | const issues = error.issues.map((issue) => { 32 | const path = issue.path.join('.') 33 | const message = issue.message 34 | return `${path}: ${message}` 35 | }) 36 | 37 | if (issues.length === 1) { 38 | return `Validation error: ${issues[0]}` 39 | } 40 | 41 | return `Validation errors:\n${issues.map((issue) => `- ${issue}`).join('\n')}` 42 | } 43 | 44 | /** 45 | * MCPサーバー設定のバリデーション 46 | */ 47 | export function validateMcpServerConfig(data: unknown): { 48 | success: boolean 49 | data?: z.infer 50 | error?: string 51 | } { 52 | const result = mcpServerConfigSchema.safeParse(data) 53 | 54 | if (result.success) { 55 | return { success: true, data: result.data } 56 | } 57 | 58 | return { success: false, error: formatZodError(result.error) } 59 | } 60 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/utils/formEventUtils.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | /** 4 | * フォーム関連のイベント処理を統一化するユーティリティ 5 | */ 6 | export const formEventUtils = { 7 | /** 8 | * イベント伝播を防止する関数 - 特定の要素は除外 9 | */ 10 | preventPropagation: (e: React.SyntheticEvent) => { 11 | // カラーピッカーなど特定の要素に対しては処理をスキップ 12 | if ( 13 | (e.target instanceof HTMLInputElement && e.target.type === 'color') || 14 | (e.target instanceof Element && e.target.closest('.color-picker-container')) 15 | ) { 16 | return e 17 | } 18 | 19 | e.preventDefault() 20 | e.stopPropagation() 21 | return e 22 | }, 23 | 24 | /** 25 | * イベント伝播を防止しつつ指定したハンドラーを呼び出す関数を返す 26 | */ 27 | createSafeHandler: 28 | (handler?: (e: T) => void) => 29 | (e: T) => { 30 | e.preventDefault() 31 | e.stopPropagation() 32 | if (handler) { 33 | handler(e) 34 | } 35 | }, 36 | 37 | /** 38 | * イベント伝播を防止しつつ提出処理を行うハンドラーを作成 39 | */ 40 | createSubmitHandler: (handler: (e: React.FormEvent) => void) => (e: React.FormEvent) => { 41 | e.stopPropagation() 42 | handler(e) 43 | }, 44 | 45 | /** 46 | * タブ切り替えハンドラーを作成 47 | */ 48 | createTabChangeHandler: 49 | ( 50 | setActiveTab: (tabId: string) => void, 51 | tabId: string, 52 | additionalAction?: () => Promise | void 53 | ) => 54 | async (e: React.MouseEvent) => { 55 | e.preventDefault() 56 | e.stopPropagation() 57 | setActiveTab(tabId) 58 | if (additionalAction) { 59 | await additionalAction() 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useSystemPromptModal.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import MD from '@renderer/components/Markdown/MD' 3 | import { Modal } from 'flowbite-react' 4 | 5 | interface SystemPromptModalProps { 6 | isOpen: boolean 7 | onClose: () => void 8 | systemPrompt: string 9 | } 10 | 11 | export const useSystemPromptModal = () => { 12 | const [show, setShow] = useState(false) 13 | const handleOpen = () => { 14 | setShow(true) 15 | } 16 | const handleClose = () => { 17 | setShow(false) 18 | } 19 | 20 | return { 21 | show: show, 22 | handleOpen: handleOpen, 23 | handleClose: handleClose, 24 | SystemPromptModal: SystemPromptModal 25 | } 26 | } 27 | 28 | const SystemPromptModal = React.memo( 29 | ({ isOpen, onClose, systemPrompt }: SystemPromptModalProps) => { 30 | if (!isOpen) return null 31 | 32 | return ( 33 | 34 |
35 | 36 | SYSTEM PROMPT 37 | 38 | 39 |
40 | {systemPrompt} 41 |
42 |
43 |
44 |
45 | ) 46 | } 47 | ) 48 | 49 | SystemPromptModal.displayName = 'SystemPromptModal' 50 | -------------------------------------------------------------------------------- /src/renderer/src/pages/WebsiteGeneratorPage/components/RecommendChanges.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { motion } from 'framer-motion' 3 | import LoadingDotsLottie from '../LoadingDots.lottie' 4 | 5 | interface Recommendation { 6 | title: string 7 | value: string 8 | } 9 | 10 | interface RecommendChangesProps { 11 | loading: boolean 12 | recommendations: Recommendation[] 13 | onSelect: (value: string) => void 14 | loadingText: string 15 | } 16 | 17 | export const RecommendChanges: React.FC = ({ 18 | loading, 19 | recommendations, 20 | onSelect, 21 | loadingText 22 | }) => { 23 | if (loading) { 24 | return ( 25 |
26 | 27 | {loadingText} 28 |
29 | ) 30 | } 31 | 32 | return ( 33 |
34 | {recommendations?.map((recommendation, index) => ( 35 | onSelect(recommendation.value)} 42 | > 43 | {recommendation.title} 44 | 45 | ))} 46 |
47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/hooks/useToolsFormatter.ts: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next' 2 | import { useMemo } from 'react' 3 | import { McpServerConfig } from '@/types/agent-chat' 4 | import { isMcpTool } from '@/types/tools' 5 | 6 | /** 7 | * ツール情報の表示に関連するフォーマット関数を提供するカスタムフック 8 | */ 9 | export function useToolsFormatter(mcpServers: McpServerConfig[] = []) { 10 | const { t } = useTranslation() 11 | 12 | /** 13 | * 選択されたツールの詳細情報を取得 14 | */ 15 | const getToolDescription = useMemo( 16 | () => 17 | (toolName: string | null): string => { 18 | if (!toolName || !isMcpTool(toolName)) return '' 19 | 20 | // MCP ツールの場合のみ説明を返す 21 | return t('MCP tool from Model Context Protocol server') 22 | }, 23 | [t] 24 | ) 25 | 26 | /** 27 | * MCP ツールのサーバー情報を取得 28 | */ 29 | const getMcpServerInfo = useMemo( 30 | () => 31 | (toolName: string | null): string => { 32 | if (!toolName || !isMcpTool(toolName) || !mcpServers || mcpServers.length === 0) return '' 33 | 34 | // 元のツール名をそのまま使用する新形式では、どのサーバーからのツールかを特定する必要がある 35 | // 複数のサーバーに同じ名前のツールがある場合は、最初に見つかったものを使用 36 | const server = mcpServers.find((_s) => { 37 | // サーバーからツールリストを取得できる場合の判定ロジックは後で実装 38 | // 現在は設定されたサーバーがあれば表示する 39 | return true 40 | }) 41 | 42 | return server 43 | ? `${t('From')}: ${server.name} (${server.description || 'MCP Server'})` 44 | : `${t('From')}: MCP Server` 45 | }, 46 | [mcpServers, t] 47 | ) 48 | 49 | return { 50 | getToolDescription, 51 | getMcpServerInfo 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/utils/toolCategories.ts: -------------------------------------------------------------------------------- 1 | import { ToolCategory } from '../types' 2 | 3 | /** 4 | * 利用可能なツールカテゴリの定義 5 | */ 6 | export const TOOL_CATEGORIES: ToolCategory[] = [ 7 | { 8 | id: 'file-system', 9 | name: 'File System', 10 | description: 'Tools for managing files and directories', 11 | tools: [ 12 | 'createFolder', 13 | 'writeToFile', 14 | 'readFiles', 15 | 'listFiles', 16 | 'moveFile', 17 | 'copyFile', 18 | 'applyDiffEdit' 19 | ] 20 | }, 21 | { 22 | id: 'web-interaction', 23 | name: 'Web & Search', 24 | description: 'Tools for interacting with web resources', 25 | tools: ['tavilySearch', 'fetchWebsite'] 26 | }, 27 | { 28 | id: 'ai-services', 29 | name: 'AI Services', 30 | description: 'Tools that utilize AWS AI services', 31 | tools: [ 32 | 'generateImage', 33 | 'generateVideo', 34 | 'recognizeImage', 35 | 'retrieve', 36 | 'invokeBedrockAgent', 37 | 'invokeFlow' 38 | ] 39 | }, 40 | { 41 | id: 'system', 42 | name: 'System', 43 | description: 'Tools for system interaction', 44 | tools: ['executeCommand', 'codeInterpreter', 'screenCapture', 'cameraCapture'] 45 | }, 46 | { 47 | id: 'thinking', 48 | name: 'Thinking', 49 | description: 'Tools for enhanced reasoning and complex problem solving', 50 | tools: ['think', 'todo'] 51 | }, 52 | { 53 | id: 'mcp', 54 | name: 'MCP', 55 | description: 'Model Context Protocol Tools', 56 | // MCPツールは動的に取得するので空配列として定義 57 | tools: [], 58 | isMcpCategory: true 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/ThinkToolSettingForm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | 4 | export const ThinkToolSettingForm: React.FC = () => { 5 | const { t } = useTranslation() 6 | 7 | return ( 8 |
9 |
10 |

11 | {t('Think Tool')} 12 |

13 |

14 | {t( 15 | 'The think tool gives the AI a dedicated space to reason through complex problems during a conversation, without changing data or fetching new information.' 16 | )} 17 |

18 |
19 | 20 |
21 |
{t('How to use')}
22 |

23 | {t( 24 | 'The think tool provides a dedicated space for the AI to stop and think during complex tasks. It helps the AI analyze information, plan next steps, and make better decisions without changing any data or fetching new information. Especially useful for multi-step problems and policy compliance.' 25 | )} 26 |

27 |

28 | {t( 29 | 'Especially useful for multi-step problems and policy compliance. The AI will automatically use this tool when needed for complex reasoning.' 30 | )} 31 |

32 |
33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /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/common/utils/placeholderUtils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Placeholder replacement utilities 3 | * Provides consistent placeholder replacement functionality across main and renderer processes 4 | */ 5 | 6 | import { CommandConfig, FlowConfig, WindowConfig, KnowledgeBase } from '../../types/agent-chat' 7 | import { BedrockAgent } from '../../types/agent' 8 | import { CameraConfig } from '../../types/tools' 9 | 10 | export interface PlaceholderValues { 11 | projectPath: string 12 | allowedCommands?: CommandConfig[] 13 | allowedWindows?: WindowConfig[] 14 | allowedCameras?: CameraConfig[] 15 | knowledgeBases?: KnowledgeBase[] 16 | bedrockAgents?: BedrockAgent[] 17 | flows?: FlowConfig[] 18 | } 19 | 20 | /** 21 | * Replace placeholders in text with provided values 22 | */ 23 | export function replacePlaceholders(text: string, placeholders: PlaceholderValues): string { 24 | const { 25 | projectPath, 26 | allowedCommands = [], 27 | allowedWindows = [], 28 | allowedCameras = [], 29 | knowledgeBases = [], 30 | bedrockAgents = [], 31 | flows = [] 32 | } = placeholders 33 | 34 | const yyyyMMdd = new Date().toISOString().slice(0, 10) 35 | 36 | return text 37 | .replace(/{{projectPath}}/g, projectPath) 38 | .replace(/{{date}}/g, yyyyMMdd) 39 | .replace(/{{allowedCommands}}/g, JSON.stringify(allowedCommands)) 40 | .replace(/{{allowedWindows}}/g, JSON.stringify(allowedWindows)) 41 | .replace(/{{allowedCameras}}/g, JSON.stringify(allowedCameras)) 42 | .replace(/{{knowledgeBases}}/g, JSON.stringify(knowledgeBases)) 43 | .replace(/{{bedrockAgents}}/g, JSON.stringify(bedrockAgents)) 44 | .replace(/{{flows}}/g, JSON.stringify(flows)) 45 | } 46 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentForm/ToolsSection/components/AvailableToolsTab/CategorySelector.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | import { CategorySelectorProps } from '../../types' 4 | 5 | /** 6 | * ツールカテゴリ選択コンポーネント 7 | */ 8 | export const CategorySelector: React.FC = ({ 9 | selectedCategory, 10 | onChange 11 | }) => { 12 | const { t } = useTranslation() 13 | 14 | return ( 15 |
16 |
17 | 20 | 33 |
34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/TaskTable/TaskTableHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface TaskTableHeaderProps { 4 | // i18n labels 5 | nameLabel: string 6 | scheduleLabel: string 7 | agentLabel: string 8 | statusLabel: string 9 | lastRunLabel: string 10 | actionsLabel: string 11 | } 12 | 13 | export const TaskTableHeader: React.FC = ({ 14 | nameLabel, 15 | scheduleLabel, 16 | agentLabel, 17 | statusLabel, 18 | lastRunLabel, 19 | actionsLabel 20 | }) => { 21 | return ( 22 | 23 | 24 | 25 | {nameLabel} 26 | 27 | 28 | {scheduleLabel} 29 | 30 | 31 | {agentLabel} 32 | 33 | 34 | {statusLabel} 35 | 36 | 37 | {lastRunLabel} 38 | 39 | 40 | {actionsLabel} 41 | 42 | 43 | 44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/ModelSelector/claude-color.svg: -------------------------------------------------------------------------------- 1 | Claude -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/ExampleScenarios/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { motion } from 'framer-motion' 3 | import { Scenario } from '@/types/agent-chat' 4 | import { useTranslation } from 'react-i18next' 5 | import { replacePlaceholders } from '../../../../../../common/utils/placeholderUtils' 6 | import { useSettings } from '@renderer/contexts/SettingsContext' 7 | 8 | type ExampleScenariosProps = { 9 | scenarios?: Scenario[] 10 | onSelectScenario: (content: string) => void 11 | } 12 | 13 | export const ExampleScenarios: React.FC = ({ 14 | scenarios = [], 15 | onSelectScenario 16 | }) => { 17 | const { t } = useTranslation() 18 | const { projectPath } = useSettings() 19 | if (scenarios.length === 0) { 20 | return null 21 | } 22 | 23 | return ( 24 |
25 | {scenarios.map((scenario, index) => ( 26 | 33 | onSelectScenario( 34 | replacePlaceholders( 35 | scenario.content === '' ? t(`${scenario.title} description`) : scenario.content, 36 | { 37 | projectPath: projectPath 38 | } 39 | ) 40 | ) 41 | } 42 | > 43 | {t(scenario.title)} 44 | 45 | ))} 46 |
47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /src/renderer/src/pages/SpeakPage/components/ToolResultDisplay.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Accordion } from 'flowbite-react' 3 | import { FaCheck } from 'react-icons/fa' 4 | import { ToolExecutionState } from '../hooks/useSpeakChat' 5 | 6 | interface ToolResultDisplayProps { 7 | toolExecutionState: ToolExecutionState 8 | } 9 | 10 | export const ToolResultDisplay: React.FC = ({ toolExecutionState }) => { 11 | if (!toolExecutionState.lastResult) { 12 | return null 13 | } 14 | 15 | const { lastResult } = toolExecutionState 16 | 17 | return ( 18 |
19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 |
27 | 完了: 28 | 29 | {lastResult.toolName} 30 | 31 |
32 |
33 |
34 | 35 |
36 |
37 |                 {JSON.stringify(lastResult.result, null, 2)}
38 |               
39 |
40 |
41 |
42 |
43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /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/renderer/src/pages/WebsiteGeneratorPage/components/KnowledgeBaseConnectButton.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import { BsDatabase, BsDatabaseCheck } from 'react-icons/bs' 3 | 4 | type KnowledgeBaseConnectButtonProps = { 5 | enableKnowledgeBase: boolean 6 | handleOpenDataSourceConnectModal: () => void 7 | } 8 | 9 | export const KnowledgeBaseConnectButton: React.FC = (props) => { 10 | const { enableKnowledgeBase, handleOpenDataSourceConnectModal } = props 11 | return ( 12 | 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/components/DomainListSection.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next' 2 | import { DomainInput } from './DomainInput' 3 | import { DomainTag } from './DomainTag' 4 | 5 | interface DomainListSectionProps { 6 | label: string 7 | domains: string[] 8 | newDomain: string 9 | error: boolean 10 | variant: 'include' | 'exclude' 11 | onDomainChange: (value: string) => void 12 | onAddDomain: () => void 13 | onRemoveDomain: (domain: string) => void 14 | onClearAll: () => void 15 | } 16 | 17 | export const DomainListSection = ({ 18 | label, 19 | domains, 20 | newDomain, 21 | error, 22 | variant, 23 | onDomainChange, 24 | onAddDomain, 25 | onRemoveDomain, 26 | onClearAll 27 | }: DomainListSectionProps) => { 28 | const { t } = useTranslation() 29 | 30 | return ( 31 |
32 |
33 | 34 | {domains.length > 0 && ( 35 | 41 | )} 42 |
43 | 44 |
45 | {domains.map((domain) => ( 46 | 47 | ))} 48 |
49 |
50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /src/renderer/src/pages/BackgroundAgentPage/components/TaskList/TaskCard/TaskStatistics.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface TaskStatisticsProps { 4 | runCount: number 5 | lastRun?: number 6 | onViewHistory: () => void 7 | formatDate: (timestamp?: number) => string 8 | // i18n labels 9 | executionCountLabel: string 10 | lastRunLabel: string 11 | viewHistoryLabel: string 12 | historyButtonTitle: string 13 | } 14 | 15 | export const TaskStatistics: React.FC = ({ 16 | runCount, 17 | lastRun, 18 | onViewHistory, 19 | formatDate, 20 | executionCountLabel, 21 | lastRunLabel, 22 | viewHistoryLabel, 23 | historyButtonTitle 24 | }) => { 25 | return ( 26 |
27 |
28 |
29 | 30 | {runCount} 31 | {executionCountLabel} 32 | 33 | 34 | {lastRunLabel}: 35 | 36 | {formatDate(lastRun)} 37 | 38 | 39 |
40 | 47 |
48 |
49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/ModelSelector/openai-color.svg: -------------------------------------------------------------------------------- 1 | 2 | OpenAI icon 3 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/TagFilter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | 4 | interface TagFilterProps { 5 | tags: string[] 6 | selectedTags: string[] 7 | onSelectTag: (tag: string) => void 8 | } 9 | 10 | export const TagFilter: React.FC = ({ tags, selectedTags, onSelectTag }) => { 11 | const { t } = useTranslation() 12 | 13 | if (tags.length === 0) { 14 | return null 15 | } 16 | 17 | return ( 18 |
19 | {tags.map((tag) => ( 20 | 31 | ))} 32 | {selectedTags.length > 0 && ( 33 | 42 | )} 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/AgentList/TagFilter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useTranslation } from 'react-i18next' 3 | 4 | interface TagFilterProps { 5 | tags: string[] 6 | selectedTags: string[] 7 | onSelectTag: (tag: string) => void 8 | } 9 | 10 | export const TagFilter: React.FC = ({ tags, selectedTags, onSelectTag }) => { 11 | const { t } = useTranslation() 12 | 13 | if (tags.length === 0) { 14 | return null 15 | } 16 | 17 | return ( 18 |
19 | {tags.map((tag) => ( 20 | 31 | ))} 32 | {selectedTags.length > 0 && ( 33 | 42 | )} 43 |
44 | ) 45 | } 46 | -------------------------------------------------------------------------------- /src/renderer/src/pages/AgentDirectoryPage/components/LoadingSkeleton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const LoadingSkeleton: React.FC = () => { 4 | return ( 5 |
6 | {[...Array(8)].map((_, index) => ( 7 |
11 |
12 | {/* アイコンスケルトン */} 13 |
14 |
15 | {/* タイトルスケルトン */} 16 |
17 | {/* 説明スケルトン */} 18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 | {/* タグスケルトン */} 26 |
27 |
28 |
29 |
30 |
31 | 32 | {/* 作者スケルトン */} 33 |
34 |
35 |
36 |
37 | ))} 38 |
39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/components/DomainInput.tsx: -------------------------------------------------------------------------------- 1 | import { useTranslation } from 'react-i18next' 2 | import { FaPlus } from 'react-icons/fa' 3 | 4 | interface DomainInputProps { 5 | value: string 6 | error: boolean 7 | onChange: (value: string) => void 8 | onAdd: () => void 9 | variant?: 'include' | 'exclude' 10 | placeholder?: string 11 | } 12 | 13 | export const DomainInput = ({ 14 | value, 15 | error, 16 | onChange, 17 | onAdd, 18 | placeholder = 'example.com' 19 | }: DomainInputProps) => { 20 | const { t } = useTranslation() 21 | 22 | const handleKeyPress = (e: React.KeyboardEvent) => { 23 | if (e.key === 'Enter' && !error) { 24 | onAdd() 25 | } 26 | } 27 | 28 | return ( 29 |
30 |
31 | onChange(e.target.value)} 35 | placeholder={placeholder} 36 | className="flex-1 px-3 py-2 text-sm border rounded dark:bg-gray-800 dark:border-gray-700 dark:text-gray-200" 37 | onKeyPress={handleKeyPress} 38 | /> 39 | 46 |
47 | {error && ( 48 |

49 | {t( 50 | 'Please enter a valid domain (e.g., example.com)', 51 | 'Please enter a valid domain (e.g., example.com)' 52 | )} 53 |

54 | )} 55 |
56 | ) 57 | } 58 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/components/InterleaveThinkingToggle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSettings } from '@renderer/contexts/SettingsContext' 3 | import { useTranslation } from 'react-i18next' 4 | import { TbBolt } from 'react-icons/tb' 5 | 6 | type InterleaveThinkingToggleProps = { 7 | className?: string 8 | } 9 | 10 | export const InterleaveThinkingToggle: React.FC = ({ 11 | className 12 | }) => { 13 | const { currentLLM, thinkingMode, interleaveThinking, setInterleaveThinking } = useSettings() 14 | const { t } = useTranslation() 15 | 16 | // Only show for Claude Sonnet 4 and Claude Opus 4 17 | const isClaude4Model = 18 | currentLLM.modelId.includes('claude-sonnet-4') || currentLLM.modelId.includes('claude-opus-4') 19 | 20 | // Only show for supported models and when thinking mode is enabled 21 | if (!isClaude4Model || thinkingMode?.type !== 'enabled') { 22 | return null 23 | } 24 | 25 | const handleToggle = () => { 26 | setInterleaveThinking(!interleaveThinking) 27 | } 28 | 29 | return ( 30 | 53 | ) 54 | } 55 | -------------------------------------------------------------------------------- /docs/mcp-server/MCP_SERVER_CONFIGURATION-ja.md: -------------------------------------------------------------------------------- 1 | # MCP サーバー設定 2 | 3 | Model Context Protocol (MCP) クライアント統合により、Bedrock Engineerは外部のMCPサーバーに接続し、強力な外部ツールを動的にロードして使用することができます。この統合により、AIアシスタントがMCPサーバーが提供するツールにアクセスして利用できるようになり、その能力が拡張されます。 4 | 5 | ## 設定形式 6 | 7 | MCP サーバーの設定は、Claude Desktop互換の`claude_desktop_config.json`形式を使用します。設定はエージェント編集モーダルの「MCPサーバー」セクションから行うことができます。 8 | 9 | MCP サーバーは以下の2つの形式で設定できます: 10 | 11 | ### 1. コマンド形式(ローカルサーバー) 12 | 13 | ```json 14 | { 15 | "mcpServers": { 16 | "サーバー名": { 17 | "command": "実行コマンド", 18 | "args": ["引数1", "引数2"], 19 | "env": { 20 | "環境変数名": "値" 21 | } 22 | } 23 | } 24 | } 25 | ``` 26 | 27 | ### 2. URL形式(リモートサーバー) 28 | 29 | ```json 30 | { 31 | "mcpServers": { 32 | "サーバー名": { 33 | "url": "https://example.com/mcp-endpoint" 34 | } 35 | } 36 | } 37 | ``` 38 | 39 | ## 設定例 40 | 41 | ```json 42 | { 43 | "mcpServers": { 44 | "fetch": { 45 | "command": "uvx", 46 | "args": ["mcp-server-fetch"] 47 | }, 48 | "filesystem": { 49 | "command": "npx", 50 | "args": ["-y", "@modelcontextprotocol/server-filesystem", "~/"], 51 | "env": { 52 | "NODE_ENV": "production" 53 | } 54 | }, 55 | "DeepWiki": { 56 | "url": "https://mcp.deepwiki.com/sse" 57 | } 58 | } 59 | } 60 | ``` 61 | 62 | ## よく使用されるMCPサーバー 63 | 64 | - **fetch**: Web上のコンテンツを取得するツール 65 | - **filesystem**: ファイルシステム操作ツール 66 | - **DeepWiki**: ナレッジベース検索ツール 67 | - **git**: Git操作ツール 68 | - **postgres**: PostgreSQLデータベース操作ツール 69 | 70 | ## 設定手順 71 | 72 | 1. エージェント編集モーダルを開く 73 | 2. 「MCPサーバー」タブを選択 74 | 3. 「新しいMCPサーバーを追加」ボタンをクリック 75 | 4. 上記のJSON形式で設定を入力 76 | 5. 「接続テスト」で接続をテスト 77 | 6. 設定を保存 78 | 79 | ## トラブルシューティング 80 | 81 | **接続エラーが発生する場合:** 82 | - コマンドパスが正しいか確認 83 | - 必要な依存関係がインストールされているか確認 84 | - 環境変数が正しく設定されているか確認 85 | 86 | **設定エラーが発生する場合:** 87 | - JSON形式が正しいか確認 88 | - `mcpServers`オブジェクトが含まれているか確認 89 | - サーバー名が重複していないか確認 -------------------------------------------------------------------------------- /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 | - from: 'src/renderer/camera-preview.html' 20 | to: 'renderer/camera-preview.html' 21 | win: 22 | executableName: Bedrock Engineer 23 | nsis: 24 | artifactName: ${name}-${version}-setup.${ext} 25 | shortcutName: ${productName} 26 | uninstallDisplayName: ${productName} 27 | createDesktopShortcut: always 28 | mac: 29 | identity: '-' 30 | entitlementsInherit: build/entitlements.mac.plist 31 | extendInfo: 32 | - NSCameraUsageDescription: Application requests access to the device's camera. 33 | - NSMicrophoneUsageDescription: Application requests access to the device's microphone. 34 | - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. 35 | - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. 36 | notarize: false 37 | target: 38 | - dmg 39 | - pkg 40 | dmg: 41 | artifactName: ${name}-${version}.${ext} 42 | pkg: 43 | artifactName: ${name}-${version}.${ext} 44 | linux: 45 | target: 46 | - AppImage 47 | - snap 48 | - deb 49 | maintainer: electronjs.org 50 | category: Utility 51 | appImage: 52 | artifactName: ${name}-${version}.${ext} 53 | npmRebuild: false 54 | publish: 55 | provider: generic 56 | url: https://example.com/auto-updates 57 | -------------------------------------------------------------------------------- /src/renderer/src/pages/ChatPage/modals/useToolSettingModal/hooks/useDomainList.ts: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import { validateDomain } from '../utils/domainValidation' 3 | 4 | interface UseDomainListProps { 5 | initialDomains: string[] 6 | onUpdate: (domains: string[]) => void 7 | } 8 | 9 | interface UseDomainListReturn { 10 | domains: string[] 11 | newDomain: string 12 | error: boolean 13 | setNewDomain: (value: string) => void 14 | handleDomainChange: (value: string) => void 15 | addDomain: () => void 16 | removeDomain: (domain: string) => void 17 | clearAll: () => void 18 | } 19 | 20 | export const useDomainList = ({ 21 | initialDomains, 22 | onUpdate 23 | }: UseDomainListProps): UseDomainListReturn => { 24 | const [domains, setDomains] = useState(initialDomains) 25 | const [newDomain, setNewDomain] = useState('') 26 | const [error, setError] = useState(false) 27 | 28 | const handleDomainChange = (value: string) => { 29 | setNewDomain(value) 30 | if (value && !validateDomain(value)) { 31 | setError(true) 32 | } else { 33 | setError(false) 34 | } 35 | } 36 | 37 | const addDomain = () => { 38 | const domain = newDomain.trim() 39 | if (domain && validateDomain(domain) && !domains.includes(domain)) { 40 | const updated = [...domains, domain] 41 | setDomains(updated) 42 | setNewDomain('') 43 | setError(false) 44 | onUpdate(updated) 45 | } 46 | } 47 | 48 | const removeDomain = (domain: string) => { 49 | const updated = domains.filter((d) => d !== domain) 50 | setDomains(updated) 51 | onUpdate(updated) 52 | } 53 | 54 | const clearAll = () => { 55 | setDomains([]) 56 | onUpdate([]) 57 | } 58 | 59 | return { 60 | domains, 61 | newDomain, 62 | error, 63 | setNewDomain, 64 | handleDomainChange, 65 | addDomain, 66 | removeDomain, 67 | clearAll 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/preload/tools/handlers/bedrock/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Bedrock tools exports 3 | */ 4 | 5 | export { GenerateImageTool } from './GenerateImageTool' 6 | export { GenerateVideoTool } from './GenerateVideoTool' 7 | export { CheckVideoStatusTool } from './CheckVideoStatusTool' 8 | export { DownloadVideoTool } from './DownloadVideoTool' 9 | export { RecognizeImageTool } from './RecognizeImageTool' 10 | export { RetrieveTool } from './RetrieveTool' 11 | export { InvokeBedrockAgentTool } from './InvokeBedrockAgentTool' 12 | export { InvokeFlowTool } from './InvokeFlowTool' 13 | 14 | import type { ToolDependencies } from '../../base/types' 15 | import { GenerateImageTool } from './GenerateImageTool' 16 | import { GenerateVideoTool } from './GenerateVideoTool' 17 | import { CheckVideoStatusTool } from './CheckVideoStatusTool' 18 | import { DownloadVideoTool } from './DownloadVideoTool' 19 | import { RecognizeImageTool } from './RecognizeImageTool' 20 | import { RetrieveTool } from './RetrieveTool' 21 | import { InvokeBedrockAgentTool } from './InvokeBedrockAgentTool' 22 | import { InvokeFlowTool } from './InvokeFlowTool' 23 | 24 | /** 25 | * Factory function to create all Bedrock tools 26 | */ 27 | export function createBedrockTools(dependencies: ToolDependencies) { 28 | return [ 29 | { tool: new GenerateImageTool(dependencies), category: 'bedrock' as const }, 30 | { tool: new GenerateVideoTool(dependencies), category: 'bedrock' as const }, 31 | { tool: new CheckVideoStatusTool(dependencies), category: 'bedrock' as const }, 32 | { tool: new DownloadVideoTool(dependencies), category: 'bedrock' as const }, 33 | { tool: new RecognizeImageTool(dependencies), category: 'bedrock' as const }, 34 | { tool: new RetrieveTool(dependencies), category: 'bedrock' as const }, 35 | { tool: new InvokeBedrockAgentTool(dependencies), category: 'bedrock' as const }, 36 | { tool: new InvokeFlowTool(dependencies), category: 'bedrock' as const } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /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/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 |