├── .env.example ├── .github └── workflows │ ├── check-backend.yml │ ├── check-console.yml │ ├── check-frontend.yml │ ├── publish-deploy.yml │ ├── publish-npm.yml │ └── publish-pypi.yml ├── .gitignore ├── .idea ├── .gitignore ├── agentlabs-poc.iml ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── dictionaries │ └── kevinpiacentini.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jsLinters │ └── eslint.xml ├── modules.xml ├── prettier.xml └── vcs.xml ├── .readme ├── agentlabs-banner.jpg ├── how-it-works.jpg └── python-sdk-example.jpeg ├── LICENSE ├── Makefile ├── NOTICE ├── README.md ├── caddy └── config │ └── Caddyfile ├── cloud-proxy ├── Caddyfile └── Dockerfile ├── console ├── .dockerignore ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .idea │ ├── .gitignore │ ├── agent-ui.iml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── jsLibraryMappings.xml │ ├── jsLinters │ │ └── eslint.xml │ ├── modules.xml │ ├── prettier.xml │ └── vcs.xml ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .storybook │ ├── main.ts │ └── preview.ts ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── src │ ├── app.css │ ├── app.d.ts │ ├── app.html │ ├── index.test.ts │ ├── lib │ │ ├── assets │ │ │ └── img │ │ │ │ ├── discord-icon.svg │ │ │ │ ├── github-dark-icon.svg │ │ │ │ ├── github-icon.svg │ │ │ │ ├── gitlab-icon.svg │ │ │ │ ├── google-icon.svg │ │ │ │ ├── illustrations │ │ │ │ ├── empty-list.svg │ │ │ │ ├── no-result.svg │ │ │ │ ├── not-found.svg │ │ │ │ └── success.svg │ │ │ │ ├── logo-dark.svg │ │ │ │ ├── logo-light.svg │ │ │ │ └── microsoft-icon.svg │ │ ├── components │ │ │ ├── auth │ │ │ │ ├── GithubIcon.svelte │ │ │ │ ├── GitlabIcon.svelte │ │ │ │ ├── GoogleIcon.svelte │ │ │ │ ├── MicrosoftIcon.svelte │ │ │ │ ├── button │ │ │ │ │ └── AuthProviderButton.svelte │ │ │ │ └── types.ts │ │ │ ├── common │ │ │ │ ├── alert │ │ │ │ │ └── Alert.svelte │ │ │ │ ├── avatar │ │ │ │ │ ├── Avatar.stories.ts │ │ │ │ │ └── Avatar.svelte │ │ │ │ ├── button │ │ │ │ │ ├── Button.stories.svelte │ │ │ │ │ ├── Button.svelte │ │ │ │ │ └── button.types.ts │ │ │ │ ├── card │ │ │ │ │ ├── Card.stories.svelte │ │ │ │ │ ├── Card.svelte │ │ │ │ │ └── CardSkeleton.svelte │ │ │ │ ├── copiable │ │ │ │ │ └── CopiableTag.svelte │ │ │ │ ├── empty-state │ │ │ │ │ ├── EmptyState.svelte │ │ │ │ │ └── NotResultState.svelte │ │ │ │ ├── input │ │ │ │ │ └── Input.svelte │ │ │ │ ├── intercom │ │ │ │ │ └── Intercom.svelte │ │ │ │ ├── loading-frame │ │ │ │ │ └── LoadingFrame.svelte │ │ │ │ ├── logo │ │ │ │ │ └── AgentLabsLogo.svelte │ │ │ │ ├── markdown │ │ │ │ │ ├── markdown-code.svelte │ │ │ │ │ ├── markdown-heading.svelte │ │ │ │ │ ├── markdown-image.svelte │ │ │ │ │ ├── markdown-link.svelte │ │ │ │ │ ├── markdown-list-item.svelte │ │ │ │ │ ├── markdown-list.svelte │ │ │ │ │ ├── markdown-paragraph.svelte │ │ │ │ │ └── markdown-renderer.svelte │ │ │ │ ├── multi-select │ │ │ │ │ ├── MultiSelect.svelte │ │ │ │ │ └── types.ts │ │ │ │ ├── navigation │ │ │ │ │ ├── left-nav │ │ │ │ │ │ └── LeftNav.svelte │ │ │ │ │ ├── nav-item │ │ │ │ │ │ ├── NavItem.svelte │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── tab-nav │ │ │ │ │ │ ├── TabNav.svelte │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── top-nav │ │ │ │ │ │ ├── TopNav.svelte │ │ │ │ │ │ └── TopNavDropdown.svelte │ │ │ │ ├── skeleton │ │ │ │ │ ├── MainTitleSkeleton.svelte │ │ │ │ │ └── PageSkeleton.svelte │ │ │ │ ├── spacer │ │ │ │ │ └── Spacer.svelte │ │ │ │ ├── switch │ │ │ │ │ └── Switch.svelte │ │ │ │ ├── table │ │ │ │ │ ├── ButtonCell.svelte │ │ │ │ │ ├── CopiableCell.svelte │ │ │ │ │ ├── NormalCell.svelte │ │ │ │ │ ├── Table.svelte │ │ │ │ │ └── types.ts │ │ │ │ ├── tabs │ │ │ │ │ ├── Tabs.svelte │ │ │ │ │ └── types.ts │ │ │ │ ├── tag │ │ │ │ │ └── Tag.svelte │ │ │ │ ├── theme-switch │ │ │ │ │ └── ThemeSwitch.svelte │ │ │ │ ├── top-cover │ │ │ │ │ └── TopCover.svelte │ │ │ │ └── typography │ │ │ │ │ └── Typography.svelte │ │ │ └── project │ │ │ │ ├── agents │ │ │ │ ├── agents-grid │ │ │ │ │ └── AgentsGrid.svelte │ │ │ │ └── code-snippets │ │ │ │ │ └── onboarding.snippet.ts │ │ │ │ └── secret │ │ │ │ └── SDKSecretGenerator.svelte │ │ ├── context │ │ │ ├── AuthOnly.svelte │ │ │ ├── IntercomContext.svelte │ │ │ └── ProjectContext.svelte │ │ ├── entities │ │ │ ├── agent │ │ │ │ ├── agent-connection.ts │ │ │ │ └── agent.ts │ │ │ ├── auth-method │ │ │ │ └── auth-method-list-item.ts │ │ │ ├── member │ │ │ │ └── member.ts │ │ │ ├── project │ │ │ │ └── project.ts │ │ │ ├── sdk-secret │ │ │ │ └── sdk-secret.ts │ │ │ └── user │ │ │ │ ├── user.ts │ │ │ │ └── userConfig.ts │ │ ├── index.ts │ │ ├── routes │ │ │ └── routes.ts │ │ ├── services │ │ │ ├── .gitkeep │ │ │ ├── oauth │ │ │ │ ├── codeVerifier.ts │ │ │ │ ├── providers │ │ │ │ │ └── google.ts │ │ │ │ ├── randomState.ts │ │ │ │ ├── signInWithRedirect.ts │ │ │ │ └── types.ts │ │ │ └── telemetry │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ ├── stores │ │ │ ├── agent.ts │ │ │ ├── auth.ts │ │ │ ├── organization.ts │ │ │ ├── project.ts │ │ │ └── theme.ts │ │ ├── usecases │ │ │ ├── agents │ │ │ │ ├── createAgent.ts │ │ │ │ ├── deleteAgent.ts │ │ │ │ ├── fetchAgentDetails.ts │ │ │ │ ├── fetchAgents.ts │ │ │ │ └── renameAgent.ts │ │ │ ├── auth-methods │ │ │ │ ├── common.ts │ │ │ │ ├── fetchAuthMethod.ts │ │ │ │ ├── fetchAvailableAuthMethods.ts │ │ │ │ └── upsert.ts │ │ │ ├── common.config.ts │ │ │ ├── members │ │ │ │ └── fetchProjectMembers.ts │ │ │ ├── projects │ │ │ │ ├── create.ts │ │ │ │ ├── fetchRealtimeBackendConnections.ts │ │ │ │ └── retrieveProjectById.ts │ │ │ ├── sdk-secrets │ │ │ │ ├── fetchSecrets.ts │ │ │ │ ├── generateSecret.ts │ │ │ │ └── revokeSecret.ts │ │ │ └── users │ │ │ │ ├── fetchRequiredUserConfig.ts │ │ │ │ ├── login.ts │ │ │ │ ├── loginWithOAuthCode.ts │ │ │ │ ├── register.ts │ │ │ │ └── signInWithGoogle.ts │ │ └── utils │ │ │ ├── buildFrontendUrl.ts │ │ │ ├── clickOutside.ts │ │ │ ├── genStoreKey.ts │ │ │ ├── oauthUtils.ts │ │ │ ├── time.ts │ │ │ ├── toast.ts │ │ │ ├── unique.ts │ │ │ └── validateEnv.ts │ └── routes │ │ ├── +error.svelte │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ ├── login │ │ ├── +layout.svelte │ │ ├── +page.server.ts │ │ └── +page.svelte │ │ ├── logout │ │ └── +page.svelte │ │ ├── oauth │ │ └── handler │ │ │ └── [providerId] │ │ │ └── +page.svelte │ │ ├── onboarding │ │ ├── +layout.svelte │ │ ├── new │ │ │ ├── +layout.svelte │ │ │ ├── +page.server.ts │ │ │ └── +page.svelte │ │ └── project │ │ │ └── [projectId] │ │ │ ├── +layout.svelte │ │ │ └── ready │ │ │ ├── +layout.svelte │ │ │ └── +page.svelte │ │ ├── project │ │ ├── +layout.svelte │ │ ├── [projectId] │ │ │ ├── +layout.svelte │ │ │ ├── agent │ │ │ │ ├── [agentId] │ │ │ │ │ ├── +layout.svelte │ │ │ │ │ ├── +page.svelte │ │ │ │ │ ├── general │ │ │ │ │ │ └── +page.svelte │ │ │ │ │ └── settings │ │ │ │ │ │ └── +page.svelte │ │ │ │ └── new │ │ │ │ │ ├── +page.server.ts │ │ │ │ │ └── +page.svelte │ │ │ ├── auth │ │ │ │ ├── +layout.svelte │ │ │ │ ├── +page.svelte │ │ │ │ ├── members │ │ │ │ │ └── +page.svelte │ │ │ │ └── methods │ │ │ │ │ ├── +page.svelte │ │ │ │ │ └── [providerId] │ │ │ │ │ ├── +page.svelte │ │ │ │ │ └── +page.ts │ │ │ ├── backends │ │ │ │ ├── +layout.svelte │ │ │ │ └── +page.svelte │ │ │ ├── overview │ │ │ │ └── +page.svelte │ │ │ └── secrets │ │ │ │ ├── +layout.svelte │ │ │ │ └── +page.svelte │ │ └── overview │ │ │ └── +page.svelte │ │ ├── register │ │ ├── +layout.svelte │ │ ├── +page.server.ts │ │ └── +page.svelte │ │ └── types.ts ├── static │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon.ico │ └── favicon.png ├── svelte.config.js ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts ├── docker-compose.cloud.yml ├── docker-compose.dev.yml ├── docker-compose.yml ├── frontend ├── .dockerignore ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .idea │ ├── .gitignore │ ├── agent-ui.iml │ ├── inspectionProfiles │ │ └── Project_Default.xml │ ├── jsLibraryMappings.xml │ ├── jsLinters │ │ └── eslint.xml │ ├── modules.xml │ ├── prettier.xml │ └── vcs.xml ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .storybook │ ├── main.ts │ └── preview.ts ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── src │ ├── app.css │ ├── app.d.ts │ ├── app.html │ ├── index.test.ts │ ├── lib │ │ ├── assets │ │ │ └── img │ │ │ │ ├── agent-icon.svg │ │ │ │ ├── github-dark-icon.svg │ │ │ │ ├── github-icon.svg │ │ │ │ ├── gitlab-icon.svg │ │ │ │ ├── google-icon.svg │ │ │ │ ├── illustrations │ │ │ │ └── not-found.svg │ │ │ │ ├── logo-dark.svg │ │ │ │ ├── logo-light.svg │ │ │ │ └── microsoft-icon.svg │ │ ├── components │ │ │ ├── auth │ │ │ │ ├── GithubIcon.svelte │ │ │ │ ├── GitlabIcon.svelte │ │ │ │ ├── GoogleIcon.svelte │ │ │ │ ├── button │ │ │ │ │ └── AuthProviderButton.svelte │ │ │ │ └── types.ts │ │ │ ├── chat │ │ │ │ ├── chat-input │ │ │ │ │ └── ChatInput.svelte │ │ │ │ ├── chat-message │ │ │ │ │ ├── AgentChatMessage.svelte │ │ │ │ │ ├── Attachment.svelte │ │ │ │ │ ├── ChatMessage.svelte │ │ │ │ │ ├── DatepickerMessage │ │ │ │ │ │ ├── Datepicker.svelte │ │ │ │ │ │ └── DatepickerMessage.svelte │ │ │ │ │ ├── EChartMessage │ │ │ │ │ │ ├── EChart.svelte │ │ │ │ │ │ └── EChartMessage.svelte │ │ │ │ │ ├── LoginMessage.svelte │ │ │ │ │ ├── MessageInput.svelte │ │ │ │ │ ├── MessageInputButton.svelte │ │ │ │ │ ├── PromptMessage.svelte │ │ │ │ │ ├── SelectMessage │ │ │ │ │ │ ├── SelectMessage.svelte │ │ │ │ │ │ └── multi-select │ │ │ │ │ │ │ ├── MultiSelect.svelte │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── TypingLoader.svelte │ │ │ │ ├── chat.svelte │ │ │ │ ├── file-uploader │ │ │ │ │ └── FileUploader.svelte │ │ │ │ └── processing-status │ │ │ │ │ ├── ProcessingStatus.stories.ts │ │ │ │ │ └── ProcessingStatus.svelte │ │ │ ├── common │ │ │ │ ├── avatar │ │ │ │ │ ├── Avatar.stories.ts │ │ │ │ │ └── Avatar.svelte │ │ │ │ ├── button │ │ │ │ │ ├── Button.stories.svelte │ │ │ │ │ ├── Button.svelte │ │ │ │ │ └── button.types.ts │ │ │ │ ├── card │ │ │ │ │ ├── Card.stories.svelte │ │ │ │ │ ├── Card.svelte │ │ │ │ │ ├── CardBody.svelte │ │ │ │ │ └── CardSkeleton.svelte │ │ │ │ ├── input │ │ │ │ │ └── Input.svelte │ │ │ │ ├── letter-avatar │ │ │ │ │ └── LetterAvatar.svelte │ │ │ │ ├── loading-frame │ │ │ │ │ └── LoadingFrame.svelte │ │ │ │ ├── logo │ │ │ │ │ ├── AgentLabsLogo.svelte │ │ │ │ │ └── PoweredBy.svelte │ │ │ │ ├── navigation │ │ │ │ │ ├── left-nav │ │ │ │ │ │ ├── LeftNav.svelte │ │ │ │ │ │ └── ProfileMenu.svelte │ │ │ │ │ ├── nav-item │ │ │ │ │ │ ├── NavItem.svelte │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── tab-nav │ │ │ │ │ │ ├── TabNav.svelte │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── top-nav │ │ │ │ │ │ └── TopNav.svelte │ │ │ │ ├── spacer │ │ │ │ │ └── Spacer.svelte │ │ │ │ ├── theme-switch │ │ │ │ │ └── ThemeSwitch.svelte │ │ │ │ └── typography │ │ │ │ │ └── Typography.svelte │ │ │ ├── markdown │ │ │ │ ├── markdown-code.svelte │ │ │ │ ├── markdown-heading.svelte │ │ │ │ ├── markdown-image.svelte │ │ │ │ ├── markdown-link.svelte │ │ │ │ ├── markdown-list-item.svelte │ │ │ │ ├── markdown-list.svelte │ │ │ │ ├── markdown-paragraph.svelte │ │ │ │ └── markdown-renderer.svelte │ │ │ └── sidebar │ │ │ │ ├── Sidebar.svelte │ │ │ │ └── header │ │ │ │ └── SidebarHeader.svelte │ │ ├── context │ │ │ ├── AgentContext.svelte │ │ │ └── RealtimeContext.svelte │ │ ├── entities │ │ │ ├── agent │ │ │ │ └── agent.ts │ │ │ ├── conversation │ │ │ │ └── conversation.ts │ │ │ ├── member │ │ │ │ └── member.ts │ │ │ ├── message │ │ │ │ └── message.ts │ │ │ └── project │ │ │ │ └── public-project-config.ts │ │ ├── gates │ │ │ └── AuthOnly.svelte │ │ ├── index.ts │ │ ├── routes │ │ │ └── routes.ts │ │ ├── services │ │ │ ├── .gitkeep │ │ │ └── oauth │ │ │ │ ├── codeVerifier.ts │ │ │ │ ├── demoRedirectState.ts │ │ │ │ ├── providers │ │ │ │ └── google.ts │ │ │ │ ├── randomState.ts │ │ │ │ ├── signInWithRedirect.ts │ │ │ │ └── types.ts │ │ ├── store │ │ │ └── chat │ │ │ │ └── chat.ts │ │ ├── stores │ │ │ ├── agent.ts │ │ │ ├── auth.ts │ │ │ ├── chat.ts │ │ │ ├── conversation.ts │ │ │ ├── left-nav.ts │ │ │ ├── main-context.ts │ │ │ ├── realtime.ts │ │ │ └── theme.ts │ │ ├── usecases │ │ │ ├── agents │ │ │ │ └── fetch-agents.ts │ │ │ ├── chat │ │ │ │ └── fetch-messages.ts │ │ │ ├── conversations │ │ │ │ └── fetch-conversations.ts │ │ │ ├── members │ │ │ │ ├── initSignInWithRedirect.ts │ │ │ │ ├── loginWithOAuthCode.ts │ │ │ │ ├── requestPasswordlessEmail.ts │ │ │ │ ├── signInAnonymously.ts │ │ │ │ ├── verifyMemberOrLogout.ts │ │ │ │ └── verifyPasswordlessEmail.ts │ │ │ └── project │ │ │ │ └── retrievePublicConfig.ts │ │ └── utils │ │ │ ├── clickOutside.ts │ │ │ ├── genStoreKey.ts │ │ │ ├── oauthUtils.ts │ │ │ ├── toast.ts │ │ │ ├── unique.ts │ │ │ └── validateEnv.ts │ ├── routes │ │ ├── +layout.svelte │ │ ├── +layout.ts │ │ ├── +page.svelte │ │ ├── chat │ │ │ ├── +layout.svelte │ │ │ ├── +page.svelte │ │ │ └── c │ │ │ │ └── [conversationId] │ │ │ │ └── +page.svelte │ │ ├── logout │ │ │ └── +page.svelte │ │ ├── oauth │ │ │ ├── handler │ │ │ │ └── [providerId] │ │ │ │ │ └── +page.svelte │ │ │ └── sign-in-popup │ │ │ │ └── [providerId] │ │ │ │ └── +page.svelte │ │ ├── project-not-found │ │ │ └── +page.svelte │ │ └── types.ts │ └── services │ │ ├── agents-service.ts │ │ ├── agents.types.ts │ │ └── backend-service.ts ├── static │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── favicon.png ├── svelte.config.js ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts ├── nginx └── nginx.conf ├── scripts └── frontend-clients │ ├── .gitignore │ ├── build_for_console.sh │ ├── build_for_frontend.sh │ └── client.ts ├── sdks ├── node-sdk │ ├── .dockerignore │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .npmrc │ ├── .prettierrc │ ├── Dockerfile │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── scripts │ │ ├── build.js │ │ └── docker-entrypoint.sh │ ├── src │ │ ├── agent-message-stream.ts │ │ ├── agent.ts │ │ ├── attachment.ts │ │ ├── const.ts │ │ ├── constants.ts │ │ ├── http.ts │ │ ├── incoming-chat-message.ts │ │ ├── index.ts │ │ ├── logger.ts │ │ ├── message-attachment.ts │ │ ├── project.ts │ │ ├── realtime.ts │ │ ├── types.ts │ │ ├── types │ │ │ └── echart.ts │ │ └── utils │ │ │ └── chunk.ts │ └── tsconfig.json └── python-sdk │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── agentlabs │ ├── __init__.py │ ├── _internals │ │ ├── __init__.py │ │ ├── const.py │ │ ├── http.py │ │ ├── logger.py │ │ ├── realtime.py │ │ └── utils.py │ ├── agent.py │ ├── attachment.py │ ├── chat.py │ ├── member.py │ └── project.py │ ├── poetry.lock │ ├── pyproject.toml │ ├── scripts │ └── docker-entrypoint.sh │ └── tests │ └── __init__.py └── server ├── .dockerignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── nest-cli.json ├── openapi.yaml ├── openapitools.json ├── package-lock.json ├── package.json ├── print-oas.Dockerfile ├── prisma ├── migrations │ ├── 20231014115126_init │ │ └── migration.sql │ ├── 20231020133514_anonymous_users │ │ └── migration.sql │ ├── 20231023224256_add_size_bytes_and_project_id_fields_to_attachment │ │ └── migration.sql │ ├── 20231026115736_add_type_and_metadata_fields_to_chat_message │ │ └── migration.sql │ └── migration_lock.toml └── schema.prisma ├── scripts ├── docker-entrypoint.dev.sh ├── docker-entrypoint.sh └── print-oas-docker-entrypoint.sh ├── src ├── agents │ ├── agents.constants.ts │ ├── agents.controller.spec.ts │ ├── agents.controller.ts │ ├── agents.errors.ts │ ├── agents.module.ts │ ├── agents.service.spec.ts │ ├── agents.service.ts │ └── dtos │ │ ├── agent-connection.dto.ts │ │ ├── create.agent.dto.ts │ │ ├── created.agent.dto.ts │ │ ├── deleted.agent.response.dto.ts │ │ ├── did-agent-ever-connect.dto.ts │ │ ├── get.agent.response.dto.ts │ │ ├── list-agent-connections.response.dto.ts │ │ ├── list.agents.response.dto.ts │ │ ├── update.agent.dto.ts │ │ └── updated.agent.dto.ts ├── app.controller.spec.ts ├── app.controller.ts ├── app.module.ts ├── app.service.ts ├── attachments │ ├── attachment-storage │ │ ├── attachment-storage.service.ts │ │ └── local-attachment-storage │ │ │ └── local-attachment-storage.service.ts │ ├── attachments.controller.spec.ts │ ├── attachments.controller.ts │ ├── attachments.module.ts │ ├── attachments.service.ts │ └── attachments.types.ts ├── auth-methods │ ├── auth-methods.config.ts │ ├── auth-methods.controller.spec.ts │ ├── auth-methods.controller.ts │ ├── auth-methods.errors.ts │ ├── auth-methods.module.ts │ ├── auth-methods.service.spec.ts │ ├── auth-methods.service.ts │ └── dtos │ │ ├── auth-method.item.dto.ts │ │ ├── create.auth-method.dto.ts │ │ ├── created.auth-method.dto.ts │ │ ├── created.demo.auth-method.dto.ts │ │ ├── list.auth-method.response.dto.ts │ │ ├── sanitized-auth-method-item.dto.ts │ │ ├── upsert.auth-method.dto.ts │ │ └── upserted.auth-method.dto.ts ├── chat-messages │ ├── chat-messages.controller.ts │ ├── chat-messages.module.ts │ ├── chat-messages.service.ts │ └── chat-messages.types.ts ├── common │ ├── base-realtime-message.dto.ts │ ├── list.response.ts │ ├── mime.ts │ ├── ms-time.ts │ ├── mutex.ts │ ├── paginated.query.dto.ts │ ├── paginated.response.ts │ ├── realtime-message.ts │ ├── result.ts │ └── tutorial-message-factory.ts ├── config │ ├── config.module.ts │ └── validate-env.ts ├── conversations │ ├── conversations.controller.ts │ ├── conversations.module.ts │ ├── conversations.service.ts │ ├── conversations.types.ts │ └── dto │ │ └── get-all-conversations.dto.ts ├── frontend-connection-manager │ ├── frontend-connection-manager.constants.ts │ ├── frontend-connection-manager.module.ts │ ├── frontend-connection-manager.service.ts │ └── frontend-connection-manager.types.ts ├── frontend-connection │ ├── dto │ │ └── frontend-chat-message.dto.ts │ ├── frontend-connection.gateway.ts │ └── frontend-connection.module.ts ├── iam │ ├── iam.decorators.ts │ ├── iam.guard.ts │ ├── iam.module.ts │ ├── iam.types.ts │ ├── member-auth │ │ └── member-auth.middleware.ts │ ├── server-sdk-auth │ │ ├── server-sdk-auth.middleware.ts │ │ └── server-sdk-auth.types.ts │ └── user-auth │ │ └── user-auth.middleware.ts ├── mailer │ ├── mailer.config.ts │ ├── mailer.module.ts │ ├── mailer.service.spec.ts │ └── mailer.service.ts ├── main.ts ├── members │ ├── dtos │ │ ├── list.members.response.dto.ts │ │ ├── login.member.response.dto.ts │ │ ├── member.whoami.result.dto.ts │ │ ├── oauth.authorize.dto.ts │ │ ├── register.response.dto.ts │ │ ├── request.passwordless-email.dto.ts │ │ ├── sanitized.member.dto.ts │ │ └── verify-passwordless-email.dto.ts │ ├── members.config.ts │ ├── members.controller.spec.ts │ ├── members.controller.ts │ ├── members.errors.ts │ ├── members.module.ts │ ├── members.service.spec.ts │ ├── members.service.ts │ ├── members.types.ts │ └── templates │ │ └── passwordless-authentication.hbs ├── oauth-providers │ ├── google │ │ ├── google.service.spec.ts │ │ ├── google.service.ts │ │ └── types.ts │ └── oauth-providers.module.ts ├── openapi-tools │ ├── index.ts │ ├── openapi-file-generator │ │ ├── openapi-file-generator.service.spec.ts │ │ └── openapi-file-generator.service.ts │ ├── openapi-nest.factory.ts │ ├── openapi-tools.module.ts │ └── openapi.service.ts ├── prisma │ ├── prisma.module.ts │ └── prisma.service.ts ├── project-backend-connection-manager │ ├── dto │ │ ├── register-agent-connection.dto.ts │ │ └── serialized-project-backend-connection.dto.ts │ ├── project-backend-connection-manager.constants.ts │ ├── project-backend-connection-manager.controller.ts │ ├── project-backend-connection-manager.module.ts │ ├── project-backend-connection-manager.service.ts │ └── project-backend-connection-manager.types.ts ├── project-backend-connection │ ├── agent-stream-manager │ │ └── agent-stream-manager.service.ts │ ├── conversation-mutex-manager.ts │ ├── dto │ │ ├── agent-message.dto.ts │ │ └── stream-chat-message-token.dto.ts │ ├── project-backend-connection.gateway.ts │ └── project-backend-connection.module.ts ├── projects │ ├── dtos │ │ ├── create.project.dto.ts │ │ ├── created.project.dto.ts │ │ ├── get-realtime-connections.response.dto.ts │ │ ├── get.public.config.dto.ts │ │ ├── list.projects.result.dto.ts │ │ ├── project.dto.ts │ │ ├── project.exists.response.dto.ts │ │ └── public.project.config.dto.ts │ ├── projects.config.ts │ ├── projects.controller.ts │ ├── projects.errors.ts │ ├── projects.module.ts │ ├── projects.service.ts │ └── projects.types.ts ├── sdk-secrets │ ├── dtos │ │ ├── create.sdk-secret.dto.ts │ │ ├── created.sdk-secret.dto.ts │ │ ├── list.sdk-secret.dto.ts │ │ ├── revoke.sdk-secret.dto.ts │ │ └── sanitized.sdk-secret.dto.ts │ ├── sdk-secrets.controller.ts │ ├── sdk-secrets.errors.ts │ ├── sdk-secrets.module.ts │ └── sdk-secrets.service.ts ├── telemetry │ ├── telemetry.config.ts │ ├── telemetry.module.ts │ ├── telemetry.service.spec.ts │ ├── telemetry.service.ts │ └── telemetry.types.ts └── users │ ├── dtos │ ├── login.response.dto.ts │ ├── login.user.dto.ts │ ├── login.user.response.dto.ts │ ├── oauth.authorize.dto.ts │ ├── oauthlogin.user.response.dto.ts │ ├── register.user.dto.ts │ ├── sanitized.user.response.dto.ts │ ├── user.created.response.dto.ts │ └── whoami.result.dto.ts │ ├── templates │ └── .gitkeep │ ├── users.config.ts │ ├── users.controller.ts │ ├── users.module.ts │ ├── users.service.errors.ts │ ├── users.service.ts │ └── users.types.ts ├── test ├── app.e2e-spec.ts └── jest-e2e.json ├── tsconfig.build.json └── tsconfig.json /.github/workflows/check-backend.yml: -------------------------------------------------------------------------------- 1 | env: 2 | BUILD_CONTEXT: server 3 | 4 | name: Check backend 5 | 6 | on: 7 | workflow_dispatch: 8 | pull_request: 9 | push: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - name: Build and push 20 | uses: docker/build-push-action@v5 21 | with: 22 | context: ${{ env.BUILD_CONTEXT }} 23 | push: false 24 | -------------------------------------------------------------------------------- /.github/workflows/check-console.yml: -------------------------------------------------------------------------------- 1 | env: 2 | BUILD_CONTEXT: console 3 | 4 | name: Check console 5 | 6 | on: 7 | workflow_dispatch: 8 | pull_request: 9 | push: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | # Required to compile the client SDKS on runners without built-in node suppot 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version: '>= 20' 23 | 24 | - name: Compile SDKs 25 | run: | 26 | OPENAPI_BASE=/api make frontend-clients 27 | 28 | - name: Build and push 29 | uses: docker/build-push-action@v5 30 | with: 31 | context: ${{ env.BUILD_CONTEXT }} 32 | push: false 33 | -------------------------------------------------------------------------------- /.github/workflows/check-frontend.yml: -------------------------------------------------------------------------------- 1 | env: 2 | BUILD_CONTEXT: frontend 3 | 4 | name: Check frontend 5 | 6 | on: 7 | workflow_dispatch: 8 | pull_request: 9 | push: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | # Required to compile the client SDKS on runners without built-in node suppot 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version: '>= 20' 23 | 24 | - name: Compile SDKs 25 | run: | 26 | OPENAPI_BASE=/api make frontend-clients 27 | 28 | - name: Build and push 29 | uses: docker/build-push-action@v5 30 | with: 31 | context: ${{ env.BUILD_CONTEXT }} 32 | push: false 33 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm.yml: -------------------------------------------------------------------------------- 1 | name: Publish node sdk 2 | env: 3 | PUBLISHER_IMAGE_TAG: node-sdk-publisher 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | publish_npm: 13 | runs-on: ubuntu-latest 14 | if: startsWith(github.ref, 'refs/tags/v') 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Build node sdk publisher image 18 | run: | 19 | docker build sdks/node-sdk -t $PUBLISHER_IMAGE_TAG 20 | - name: Publish node client 21 | run: > 22 | docker run 23 | --rm 24 | -e NPM_TOKEN="${{ secrets.NPM_TOKEN }}" 25 | -e VERSION="$( echo ${{ github.ref_name }} | tr -d 'v' )" 26 | $PUBLISHER_IMAGE_TAG 27 | -------------------------------------------------------------------------------- /.github/workflows/publish-pypi.yml: -------------------------------------------------------------------------------- 1 | name: Publish python sdk 2 | env: 3 | PUBLISHER_IMAGE_TAG: python-sdk-publisher 4 | 5 | on: 6 | push: 7 | tags: 8 | - "v*" 9 | workflow_dispatch: 10 | 11 | jobs: 12 | publish_pypi: 13 | runs-on: ubuntu-latest 14 | if: startsWith(github.ref, 'refs/tags/v') 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Build python sdk publisher image 18 | run: | 19 | docker build sdks/python-sdk -t $PUBLISHER_IMAGE_TAG 20 | - name: Publish python client (tag version) 21 | run: > 22 | docker run 23 | --rm 24 | -e PYPI_TOKEN="${{ secrets.PYPI_TOKEN }}" 25 | -e VERSION="$( echo ${{ github.ref_name }} | tr -d 'v' )" 26 | $PUBLISHER_IMAGE_TAG 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .env.local 3 | node_modules 4 | 5 | gen-api 6 | caddy/data 7 | 8 | /attachments 9 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/agentlabs-poc.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/dictionaries/kevinpiacentini.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.readme/agentlabs-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/.readme/agentlabs-banner.jpg -------------------------------------------------------------------------------- /.readme/how-it-works.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/.readme/how-it-works.jpg -------------------------------------------------------------------------------- /.readme/python-sdk-example.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/.readme/python-sdk-example.jpeg -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @echo "make frontend-clients" 3 | @echo "make openapi" 4 | 5 | frontend-clients: openapi 6 | cd scripts/frontend-clients && ./build_for_frontend.sh 7 | cd scripts/frontend-clients && ./build_for_console.sh 8 | .PHONY: build-frontend-clients 9 | 10 | openapi: 11 | docker build -f ./server/print-oas.Dockerfile -t print-oas ./server 12 | docker run --rm print-oas > ./server/openapi.yaml 13 | docker rmi print-oas 14 | .PHONY: gen-oas 15 | 16 | check: check-frontend check-backend check-console 17 | .PHONY: check 18 | 19 | check-frontend: 20 | cd frontend && npm run check 21 | .PHONY: check-frontend 22 | 23 | check-backend: 24 | cd server && npm run build 25 | .PHONY: check-backend 26 | 27 | check-console: 28 | cd console && npm run check 29 | .PHONY: check-console 30 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 AgentLabs, Inc 2 | 3 | Source code in this repository is licensed under the Apache License 4 | Version 2.0. Please see LICENSE for more information. 5 | 6 | Every file is under copyright (c) 2023 AgentLabs, Inc unless otherwise 7 | specified. 8 | 9 | * For a copy of the Apache License Version 2.0, please see LICENSE 10 | as included in this repository's top-level directory. 11 | 12 | * All third party components incorporated into the AgentLabs Software are licensed 13 | under the original license provided by the owner of the applicable component. -------------------------------------------------------------------------------- /caddy/config/Caddyfile: -------------------------------------------------------------------------------- 1 | :80 { 2 | handle_path /api { 3 | reverse_proxy server:3000 4 | } 5 | 6 | handle_path /api/* { 7 | reverse_proxy server:3000 8 | } 9 | 10 | handle /socket.io/* { 11 | reverse_proxy server:3000 12 | } 13 | 14 | handle /admin { 15 | reverse_proxy console:3000 16 | } 17 | 18 | handle /admin/* { 19 | reverse_proxy console:3000 20 | } 21 | 22 | handle { 23 | reverse_proxy frontend:3000 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /cloud-proxy/Caddyfile: -------------------------------------------------------------------------------- 1 | {$CLOUD_APP_DOMAIN}:443 { 2 | reverse_proxy gateway 3 | } 4 | 5 | {$CLOUD_APP_WILDCARD_DOMAIN}:443 { 6 | tls { 7 | dns godaddy {$CLOUD_APP_WILDCARD_DOMAIN_DNS_API_KEY} 8 | } 9 | 10 | reverse_proxy gateway 11 | } 12 | 13 | {$CLOUD_CONSOLE_DOMAIN}:443 { 14 | @console { 15 | path /admin/* 16 | } 17 | 18 | @api { 19 | path /api/* 20 | } 21 | 22 | handle @console { 23 | reverse_proxy gateway 24 | } 25 | 26 | handle @api { 27 | reverse_proxy gateway 28 | } 29 | 30 | handle { 31 | redir * /admin{path} 32 | reverse_proxy gateway 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /cloud-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM caddy:2.7.4-builder-alpine as builder 2 | 3 | RUN xcaddy build \ 4 | --with github.com/caddy-dns/godaddy 5 | 6 | FROM caddy:2.7.4-alpine 7 | 8 | COPY --from=builder /usr/bin/caddy /usr/bin/caddy 9 | -------------------------------------------------------------------------------- /console/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | .git 4 | .gitignore 5 | .gitattributes 6 | README.md 7 | .npmrc 8 | .prettierrc 9 | .eslintrc.cjs 10 | .graphqlrc 11 | .editorconfig 12 | .svelte-kit 13 | .vscode 14 | node_modules 15 | build 16 | package 17 | **/.env 18 | -------------------------------------------------------------------------------- /console/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /console/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | "eslint:recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "plugin:svelte/recommended", 7 | "prettier", 8 | "plugin:storybook/recommended", 9 | "plugin:storybook/recommended" 10 | ], 11 | parser: '@typescript-eslint/parser', 12 | plugins: ['@typescript-eslint'], 13 | parserOptions: { 14 | sourceType: 'module', 15 | ecmaVersion: 2020, 16 | extraFileExtensions: ['.svelte'] 17 | }, 18 | env: { 19 | browser: true, 20 | es2017: true, 21 | node: true 22 | }, 23 | overrides: [ 24 | { 25 | files: ['*.svelte'], 26 | parser: 'svelte-eslint-parser', 27 | parserOptions: { 28 | parser: '@typescript-eslint/parser' 29 | } 30 | } 31 | ] 32 | }; 33 | -------------------------------------------------------------------------------- /console/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /console/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /console/.idea/agent-ui.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /console/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /console/.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /console/.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /console/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /console/.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /console/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /console/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /console/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /console/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "trailingComma": "none", 4 | "tabWidth": 4, 5 | "printWidth": 100, 6 | "semi": true, 7 | "singleQuote": false, 8 | "jsxBracketSameLine": true, 9 | "plugins": ["prettier-plugin-organize-imports"], 10 | "overrides": [ { 11 | "files": "*.svelte", 12 | "options": { 13 | "svelteBracketNewLine": false, 14 | "svelteAllowShorthand": false, 15 | "svelteSortOrder" : "options-scripts-styles-markup", 16 | "plugins": [ "prettier-plugin-svelte" ] 17 | } 18 | } ], 19 | "pluginSearchDirs": [ "." ] 20 | } -------------------------------------------------------------------------------- /console/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from "@storybook/sveltekit"; 2 | 3 | const config: StorybookConfig = { 4 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)"], 5 | addons: [ 6 | "@storybook/addon-svelte-csf", 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions", 10 | { 11 | name: "@storybook/addon-styling", 12 | options: {} 13 | } 14 | ], 15 | framework: { 16 | name: "@storybook/sveltekit", 17 | options: {} 18 | }, 19 | docs: { 20 | autodocs: "tag" 21 | } 22 | }; 23 | export default config; 24 | -------------------------------------------------------------------------------- /console/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from "@storybook/svelte"; 2 | 3 | import { withThemeByClassName } from "@storybook/addon-styling"; 4 | 5 | import "../src/app.css"; 6 | 7 | const preview: Preview = { 8 | parameters: { 9 | actions: { argTypesRegex: "^on[A-Z].*" }, 10 | controls: { 11 | matchers: { 12 | color: /(background|color)$/i, 13 | date: /Date$/ 14 | } 15 | } 16 | }, 17 | 18 | decorators: [ 19 | // Adds theme switching support. 20 | // NOTE: requires setting "darkMode" to "class" in your tailwind config 21 | withThemeByClassName({ 22 | themes: { 23 | light: "light", 24 | dark: "dark" 25 | }, 26 | defaultTheme: "light" 27 | }) 28 | ] 29 | }; 30 | 31 | export default preview; 32 | -------------------------------------------------------------------------------- /console/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as build-stage 2 | 3 | WORKDIR /app 4 | 5 | COPY package*.json . 6 | 7 | RUN npm ci 8 | 9 | COPY . . 10 | 11 | RUN npm run check 12 | 13 | RUN npm run build 14 | 15 | RUN npm prune --production 16 | 17 | FROM node:20-alpine3.17 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=build-stage /app/build build/ 22 | COPY --from=build-stage /app/node_modules node_modules/ 23 | COPY package.json . 24 | 25 | ENV NODE_ENV=production 26 | 27 | 28 | CMD [ "sh", "-c", "node -r dotenv/config build" ] 29 | -------------------------------------------------------------------------------- /console/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 2 | 3 | WORKDIR /app 4 | 5 | VOLUME [ "/app" ] 6 | 7 | # IMPORTANT: 8 | # As svelte kit uses vite under the hood, which itself use esbuild, it is necessary to install the deps from inside 9 | # the container as esbuild is a native dependency and it needs to be compiled for the target platform. 10 | 11 | ENTRYPOINT [ "sh", "-c", "npm install && npm run dev -- --port 3000 --host" ] 12 | -------------------------------------------------------------------------------- /console/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /console/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /console/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /console/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %sveltekit.head% 9 | 10 | 11 |
%sveltekit.body%
12 | 13 | 14 | -------------------------------------------------------------------------------- /console/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /console/src/lib/assets/img/gitlab-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /console/src/lib/assets/img/google-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /console/src/lib/assets/img/microsoft-icon.svg: -------------------------------------------------------------------------------- 1 | MS-SymbolLockup -------------------------------------------------------------------------------- /console/src/lib/components/auth/GithubIcon.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {#if $themeStore === "dark"} 8 | {"github"} 9 | {:else} 10 | {"github"} 11 | {/if} 12 | -------------------------------------------------------------------------------- /console/src/lib/components/auth/GitlabIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"gitlab"} 6 | -------------------------------------------------------------------------------- /console/src/lib/components/auth/GoogleIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"google"} 6 | -------------------------------------------------------------------------------- /console/src/lib/components/auth/MicrosoftIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"microsoft"} 6 | -------------------------------------------------------------------------------- /console/src/lib/components/auth/types.ts: -------------------------------------------------------------------------------- 1 | export const AuthProviders = ["google", "github", "gitlab"] as const; 2 | export type AuthProvider = (typeof AuthProviders)[number]; 3 | -------------------------------------------------------------------------------- /console/src/lib/components/common/alert/Alert.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /console/src/lib/components/common/avatar/Avatar.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/svelte"; 2 | 3 | import Avatar from "./Avatar.svelte"; 4 | 5 | // More on how to set up stories at: https://storybook.js.org/docs/svelte/writing-stories/introduction 6 | const meta = { 7 | title: "Common/Avatar", 8 | component: Avatar, 9 | tags: ["autodocs"] 10 | } satisfies Meta; 11 | 12 | export default meta; 13 | type Story = StoryObj; 14 | 15 | // More on writing stories with args: https://storybook.js.org/docs/svelte/writing-stories/args 16 | export const Basic: Story = { 17 | args: { 18 | alt: "Some user profile image", 19 | src: "https://media.licdn.com/dms/image/D4E03AQFXJiFpNFWE0A/profile-displayphoto-shrink_100_100/0/1680893451739?e=1699488000&v=beta&t=WiNliB67TjMHbaIycm8u55JDrX82xu9I20jw-b10u4A" 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /console/src/lib/components/common/avatar/Avatar.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | {#if image.src} 14 | { 17 | image.src = null; 18 | }} 19 | alt={alt} 20 | class="rounded-full w-9" /> 21 | {:else} 22 |
24 | 28 |
29 | {/if} 30 |
31 | -------------------------------------------------------------------------------- /console/src/lib/components/common/button/button.types.ts: -------------------------------------------------------------------------------- 1 | export const ButtonStatuses = ["disabled", "loading", "default"]; 2 | export type ButtonStatus = (typeof ButtonStatuses)[number]; 3 | -------------------------------------------------------------------------------- /console/src/lib/components/common/card/Card.stories.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /console/src/lib/components/common/card/Card.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
{}} 22 | class="{clickableClass} {disabledClass} w-full rounded-2xl border border-stroke-base dark:border-stroke-base-dark bg-background-tertiary dark:bg-background-tertiary-dark"> 23 | 24 |
25 | -------------------------------------------------------------------------------- /console/src/lib/components/common/card/CardSkeleton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |
7 |
9 |
11 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /console/src/lib/components/common/empty-state/EmptyState.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 12 |
13 | not found 14 |
15 | {title} 16 | {description} 17 |
18 | 19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /console/src/lib/components/common/empty-state/NotResultState.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 12 |
13 | not found 14 |
15 | {title} 16 | {description} 17 |
18 | 19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /console/src/lib/components/common/loading-frame/LoadingFrame.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
8 |
9 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /console/src/lib/components/common/logo/AgentLabsLogo.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | AgentLabs Logo 9 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-image.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {token.text} 12 | 13 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-link.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-list-item.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
  • 12 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-list.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | {#each token.items as item} 15 | 16 | {/each} 17 | 18 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-paragraph.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 |

    5 | 6 |

    7 | -------------------------------------------------------------------------------- /console/src/lib/components/common/markdown/markdown-renderer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 26 | -------------------------------------------------------------------------------- /console/src/lib/components/common/multi-select/types.ts: -------------------------------------------------------------------------------- 1 | import type { ComponentType } from "svelte"; 2 | import type { IconSource } from "svelte-hero-icons"; 3 | 4 | export type MultiSelectItem = { 5 | id: string; 6 | label: string; 7 | value: string; 8 | heroIcon?: IconSource; 9 | customIcon?: ComponentType; 10 | disabled?: boolean; 11 | disabledLabel?: string; 12 | selected?: boolean; 13 | required?: boolean; 14 | }; 15 | -------------------------------------------------------------------------------- /console/src/lib/components/common/navigation/nav-item/NavItem.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
  • {}} 14 | on:click={() => goto(item.path)} 15 | class="{isActive ? 'bg-background-accent dark:bg-background-accent-dark' : ''} 16 | hover:bg-background-accent dark:hover:bg-background-accent-dark text-sm text-body-base dark:text-body-base-dark py-3 px-4 rounded-lg flex gap-2 items-center cursor-pointer"> 17 | {#if item?.icon} 18 | 19 | {/if} 20 | {item.label} 21 |
  • 22 | -------------------------------------------------------------------------------- /console/src/lib/components/common/navigation/nav-item/types.ts: -------------------------------------------------------------------------------- 1 | import type { IconSource } from "svelte-hero-icons"; 2 | 3 | export type NavItemType = { 4 | path: string; 5 | label: string; 6 | icon?: IconSource; 7 | }; 8 | -------------------------------------------------------------------------------- /console/src/lib/components/common/navigation/tab-nav/types.ts: -------------------------------------------------------------------------------- 1 | export type TabNavItem = { 2 | path: string; 3 | label: string; 4 | }; 5 | -------------------------------------------------------------------------------- /console/src/lib/components/common/skeleton/MainTitleSkeleton.svelte: -------------------------------------------------------------------------------- 1 |
    3 | 4 |
    6 | -------------------------------------------------------------------------------- /console/src/lib/components/common/spacer/Spacer.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 | -------------------------------------------------------------------------------- /console/src/lib/components/common/table/ButtonCell.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
    12 | 13 |
    14 | -------------------------------------------------------------------------------- /console/src/lib/components/common/table/CopiableCell.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    8 | 9 |
    10 | -------------------------------------------------------------------------------- /console/src/lib/components/common/table/NormalCell.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | {cellValue} 8 | -------------------------------------------------------------------------------- /console/src/lib/components/common/table/types.ts: -------------------------------------------------------------------------------- 1 | import type { SvelteComponent } from "svelte"; 2 | 3 | export type TableColumn = { 4 | name: string; 5 | key: K; 6 | format?: (rowValue: T) => string; 7 | customComponent?: typeof SvelteComponent<{ cellValue: any }>; 8 | }; 9 | 10 | export type TableRow = T; 11 | -------------------------------------------------------------------------------- /console/src/lib/components/common/tabs/types.ts: -------------------------------------------------------------------------------- 1 | export type TabItem = { 2 | id: string; 3 | value: string; 4 | label: string; 5 | }; 6 | -------------------------------------------------------------------------------- /console/src/lib/components/common/top-cover/TopCover.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 |
    6 | 7 |
    8 | -------------------------------------------------------------------------------- /console/src/lib/entities/agent/agent-connection.ts: -------------------------------------------------------------------------------- 1 | export interface AgentConnection { 2 | id: string; 3 | ip: string; 4 | createdAt: string; 5 | } 6 | -------------------------------------------------------------------------------- /console/src/lib/entities/agent/agent.ts: -------------------------------------------------------------------------------- 1 | export interface Agent { 2 | id: string; 3 | name: string; 4 | createdAt: Date; 5 | updatedAt: Date; 6 | } 7 | -------------------------------------------------------------------------------- /console/src/lib/entities/auth-method/auth-method-list-item.ts: -------------------------------------------------------------------------------- 1 | import type { SvelteComponent } from "svelte"; 2 | import type { IconSource } from "svelte-hero-icons"; 3 | 4 | export type AuthMethodListItem = { 5 | id: string; 6 | name: string; 7 | value: string; 8 | heroIcon: IconSource | null; 9 | componentIcon: typeof SvelteComponent | null; 10 | available: boolean; 11 | isEnabled: boolean; 12 | statusLabel: string; 13 | }; 14 | -------------------------------------------------------------------------------- /console/src/lib/entities/member/member.ts: -------------------------------------------------------------------------------- 1 | export type Member = { 2 | id: string; 3 | firstName: string | null; 4 | lastName: string | null; 5 | email: string | null; 6 | verifiedAt: Date | null; 7 | createdAt: Date; 8 | updatedAt: Date; 9 | }; 10 | -------------------------------------------------------------------------------- /console/src/lib/entities/project/project.ts: -------------------------------------------------------------------------------- 1 | export type Project = { 2 | id: string; 3 | name: string; 4 | organizationId: string; 5 | slug: string; 6 | 7 | createdAt: Date; 8 | updatedAt: Date; 9 | }; 10 | -------------------------------------------------------------------------------- /console/src/lib/entities/sdk-secret/sdk-secret.ts: -------------------------------------------------------------------------------- 1 | export type SdkSecret = { 2 | id: string; 3 | description: string | null; 4 | hash: string; 5 | preview: string; 6 | createdAt: Date; 7 | updatedAt: Date; 8 | projectId: string; 9 | }; 10 | 11 | export type SanitizedSdkSecret = Omit; 12 | -------------------------------------------------------------------------------- /console/src/lib/entities/user/user.ts: -------------------------------------------------------------------------------- 1 | export type User = { 2 | id: string; 3 | fullName: string; 4 | profilePictureUrl: string | null; 5 | verifiedAt: Date | null; 6 | email: string; 7 | createdAt: Date; 8 | }; 9 | -------------------------------------------------------------------------------- /console/src/lib/entities/user/userConfig.ts: -------------------------------------------------------------------------------- 1 | export type UserConfig = { 2 | id: string; 3 | fullName: string; 4 | verifiedAt: Date | null; 5 | email: string; 6 | createdAt: Date; 7 | organizationCount: number; 8 | defaultOrganizationId: string | null; 9 | defaultProjectId: string | null; 10 | projectCount: number; 11 | projectCreatedCount: number; 12 | onboarding: { 13 | hasAddedAuthMethod: boolean; 14 | hasUsedTheApplication: boolean; 15 | projectId: string | null; 16 | organizationId: string; 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /console/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /console/src/lib/services/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/src/lib/services/.gitkeep -------------------------------------------------------------------------------- /console/src/lib/services/oauth/codeVerifier.ts: -------------------------------------------------------------------------------- 1 | const CODE_VERIFIER_SESSION_KEY = "agentlabs/console/oauth/code-verifier"; 2 | 3 | export const saveCodeVerifier = (codeVerifier: string): void => { 4 | sessionStorage.setItem(CODE_VERIFIER_SESSION_KEY, codeVerifier); 5 | }; 6 | 7 | export const getCodeVerifier = (): string | null => { 8 | return sessionStorage.getItem(CODE_VERIFIER_SESSION_KEY); 9 | }; 10 | -------------------------------------------------------------------------------- /console/src/lib/services/oauth/randomState.ts: -------------------------------------------------------------------------------- 1 | export const randomState = (length = 40) => { 2 | const crypto = window.crypto; 3 | const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 4 | const array = new Uint8Array(length); 5 | crypto.getRandomValues(array); 6 | const values = new Array(length); 7 | array.forEach((v, i) => { 8 | values[i] = validChars.charCodeAt(v % validChars.length); 9 | }); 10 | return String.fromCharCode.apply(null, values); 11 | }; 12 | -------------------------------------------------------------------------------- /console/src/lib/services/telemetry/types.ts: -------------------------------------------------------------------------------- 1 | export const PageCategories = ["console"] as const; 2 | 3 | export type PageCategory = (typeof PageCategories)[number]; 4 | -------------------------------------------------------------------------------- /console/src/lib/stores/agent.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | import type { Agent } from "$lib/entities/agent/agent"; 3 | 4 | export type AgentStore = { 5 | currentAgent: Agent | null; 6 | currentAgentId: string | null; 7 | }; 8 | 9 | export const agentStore = writable({ 10 | currentAgent: null, 11 | currentAgentId: null 12 | }); 13 | 14 | export const setCurrentAgent = (agent: Agent | null) => { 15 | agentStore.update((store) => { 16 | return { 17 | ...store, 18 | currentAgent: agent, 19 | currentAgentId: agent?.id ?? null 20 | }; 21 | }); 22 | }; 23 | -------------------------------------------------------------------------------- /console/src/lib/stores/organization.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | export const organizationStore = writable<{ 4 | currentOrganizationId: string | null; 5 | }>({ 6 | currentOrganizationId: null 7 | }); 8 | 9 | export const setCurrentOrganizationId = (id: string | null) => { 10 | organizationStore.update((store) => { 11 | store.currentOrganizationId = id; 12 | return store; 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /console/src/lib/stores/theme.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | import { createLocalStorage, persist } from "@macfja/svelte-persistent-store"; 3 | import { genStoreKey } from "$lib/utils/genStoreKey"; 4 | 5 | export type Theme = "light" | "dark"; 6 | 7 | const THEME_STORE_KEY = genStoreKey("theme-store"); 8 | 9 | export const themeStore = persist(writable("light"), createLocalStorage(), THEME_STORE_KEY); 10 | -------------------------------------------------------------------------------- /console/src/lib/usecases/agents/createAgent.ts: -------------------------------------------------------------------------------- 1 | import type { Agent } from "$lib/entities/agent/agent"; 2 | import { AgentsService } from "$lib/services/gen-api"; 3 | 4 | export const createAgent = async (params: { projectId: string; name: string }): Promise => { 5 | const agent = await AgentsService.createAgent({ 6 | requestBody: { 7 | projectId: params.projectId, 8 | name: params.name 9 | } 10 | }); 11 | 12 | return { 13 | ...agent, 14 | createdAt: new Date(agent.createdAt), 15 | updatedAt: new Date(agent.updatedAt) 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /console/src/lib/usecases/agents/deleteAgent.ts: -------------------------------------------------------------------------------- 1 | import { AgentsService } from "$lib/services/gen-api"; 2 | 3 | export const deleteAgent = async (agentId: string): Promise => { 4 | await AgentsService.deleteAgent({ 5 | agentId 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /console/src/lib/usecases/agents/fetchAgentDetails.ts: -------------------------------------------------------------------------------- 1 | import type { Agent } from "$lib/entities/agent/agent"; 2 | import { AgentsService } from "$lib/services/gen-api"; 3 | 4 | const waitForDelay = (delay: number) => new Promise((resolve) => setTimeout(resolve, delay)); 5 | 6 | export const fetchAgentDetails = async (agentId: string): Promise => { 7 | const item = await AgentsService.getById({ 8 | agentId 9 | }); 10 | 11 | await waitForDelay(500); 12 | 13 | return { 14 | id: item.id, 15 | name: item.name, 16 | createdAt: new Date(item.createdAt), 17 | updatedAt: new Date(item.updatedAt) 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /console/src/lib/usecases/agents/fetchAgents.ts: -------------------------------------------------------------------------------- 1 | import type { Agent } from "$lib/entities/agent/agent"; 2 | import { AgentsService } from "$lib/services/gen-api"; 3 | 4 | export const fetchAgents = async (projectId: string): Promise => { 5 | const result = await AgentsService.listForProject({ 6 | projectId 7 | }); 8 | 9 | return result.items.map((item) => ({ 10 | id: item.id, 11 | name: item.name, 12 | createdAt: new Date(item.createdAt), 13 | updatedAt: new Date(item.updatedAt) 14 | })); 15 | }; 16 | -------------------------------------------------------------------------------- /console/src/lib/usecases/agents/renameAgent.ts: -------------------------------------------------------------------------------- 1 | import type { Agent } from "$lib/entities/agent/agent"; 2 | import { AgentsService } from "$lib/services/gen-api"; 3 | import { setCurrentAgent } from "$lib/stores/agent"; 4 | 5 | export const renameAgent = async (params: { agentId: string; name: string }): Promise => { 6 | const result = await AgentsService.updateAgent({ 7 | agentId: params.agentId, 8 | requestBody: { 9 | name: params.name 10 | } 11 | }); 12 | 13 | const agent = { 14 | ...result, 15 | createdAt: new Date(result.createdAt), 16 | updatedAt: new Date(result.updatedAt) 17 | }; 18 | 19 | setCurrentAgent(agent); 20 | 21 | return agent; 22 | }; 23 | -------------------------------------------------------------------------------- /console/src/lib/usecases/auth-methods/common.ts: -------------------------------------------------------------------------------- 1 | import GoogleIcon from "$lib/components/auth/GoogleIcon.svelte"; 2 | import type { SvelteComponent } from "svelte"; 3 | import type { IconSource } from "svelte-hero-icons"; 4 | import { Envelope } from "svelte-hero-icons"; 5 | 6 | export type AvailableAuthMethod = { 7 | name: string; 8 | providerId: string; 9 | heroIcon: IconSource | null; 10 | componentIcon: typeof SvelteComponent | null; 11 | type: "EMAIL" | "OAUTH2"; 12 | }; 13 | 14 | export const availableAuthMethods: AvailableAuthMethod[] = [ 15 | { 16 | name: "Passwordless email", 17 | providerId: "PASSWORDLESS_EMAIL", 18 | heroIcon: Envelope, 19 | componentIcon: null, 20 | type: "EMAIL" 21 | }, 22 | { 23 | name: "Google / Gmail", 24 | providerId: "GOOGLE", 25 | heroIcon: null, 26 | componentIcon: GoogleIcon, 27 | type: "OAUTH2" 28 | } 29 | ]; 30 | -------------------------------------------------------------------------------- /console/src/lib/usecases/auth-methods/upsert.ts: -------------------------------------------------------------------------------- 1 | import type { UpsertAuthMethodDto } from "$lib/services/gen-api"; 2 | import { AuthMethodsService } from "$lib/services/gen-api"; 3 | 4 | export const upsertAuthMethod = async (authMethod: UpsertAuthMethodDto) => { 5 | return AuthMethodsService.upsert({ 6 | requestBody: { 7 | ...authMethod 8 | } 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /console/src/lib/usecases/common.config.ts: -------------------------------------------------------------------------------- 1 | import { OpenAPI } from "$lib/services/gen-api"; 2 | 3 | // TODO: change that to the correct base path 4 | // Or add it directly in the SDK later. 5 | OpenAPI.BASE = "http://localhost:8080/console/lolilol"; 6 | -------------------------------------------------------------------------------- /console/src/lib/usecases/projects/create.ts: -------------------------------------------------------------------------------- 1 | import { ProjectsService } from "$lib/services/gen-api"; 2 | import type { CreateProjectDto } from "$lib/services/gen-api"; 3 | import dayjs from "dayjs"; 4 | import type { Project } from "$lib/entities/project/project"; 5 | 6 | export const createProject = async (project: CreateProjectDto): Promise => { 7 | const result = await ProjectsService.createProject({ 8 | requestBody: project 9 | }); 10 | 11 | return { 12 | id: result.id, 13 | name: result.name, 14 | organizationId: result.organizationId, 15 | slug: result.slug, 16 | createdAt: dayjs(result.createdAt).toDate(), 17 | updatedAt: dayjs(result.updatedAt).toDate() 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /console/src/lib/usecases/projects/fetchRealtimeBackendConnections.ts: -------------------------------------------------------------------------------- 1 | import { ProjectsService, type SerializedProjectBackendConnectionDto } from "$lib/services/gen-api" 2 | 3 | export const fetchRealtimeConnections = async (projectId: string): Promise => { 4 | const { items } = await ProjectsService.getRealtimeConnections({ projectId }) 5 | 6 | return items 7 | } 8 | -------------------------------------------------------------------------------- /console/src/lib/usecases/projects/retrieveProjectById.ts: -------------------------------------------------------------------------------- 1 | import type { Project } from "$lib/entities/project/project"; 2 | import { ProjectsService } from "$lib/services/gen-api"; 3 | import dayjs from "dayjs"; 4 | 5 | export const retrieveProjectById = async (projectId: string): Promise => { 6 | await new Promise((resolve) => setTimeout(resolve, 500)); 7 | const result = await ProjectsService.getById({ 8 | projectId 9 | }); 10 | 11 | return { 12 | createdAt: dayjs(result.createdAt).toDate(), 13 | id: result.id, 14 | name: result.name, 15 | organizationId: result.organizationId, 16 | slug: result.slug, 17 | updatedAt: dayjs(result.updatedAt).toDate() 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /console/src/lib/usecases/sdk-secrets/fetchSecrets.ts: -------------------------------------------------------------------------------- 1 | import type { ListSdkSecretDto } from "$lib/services/gen-api"; 2 | import { SdkSecretsService } from "$lib/services/gen-api"; 3 | 4 | export const fetchSecrets = async (projectId: string): Promise => { 5 | await new Promise((resolve) => setTimeout(resolve, 500)); 6 | const secrets = await SdkSecretsService.listForProject({ 7 | projectId 8 | }); 9 | 10 | return secrets; 11 | }; 12 | -------------------------------------------------------------------------------- /console/src/lib/usecases/sdk-secrets/generateSecret.ts: -------------------------------------------------------------------------------- 1 | import type { CreatedSdkSecretDto } from "$lib/services/gen-api"; 2 | import { SdkSecretsService } from "$lib/services/gen-api"; 3 | 4 | export const generateSecret = async (projectId: string): Promise => { 5 | await new Promise((resolve) => setTimeout(resolve, 500)); 6 | const secret = await SdkSecretsService.create({ 7 | requestBody: { 8 | projectId 9 | } 10 | }); 11 | 12 | return { 13 | ...secret 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /console/src/lib/usecases/sdk-secrets/revokeSecret.ts: -------------------------------------------------------------------------------- 1 | import { SdkSecretsService } from "$lib/services/gen-api"; 2 | 3 | export const revokeSecret = async (secretId: string) => { 4 | await new Promise((resolve) => setTimeout(resolve, 500)); 5 | const result = await SdkSecretsService.revokedById({ 6 | secretId 7 | }); 8 | 9 | return result; 10 | }; 11 | -------------------------------------------------------------------------------- /console/src/lib/usecases/users/register.ts: -------------------------------------------------------------------------------- 1 | import type { User } from "$lib/entities/user/user"; 2 | import type { RegisterUserDto } from "$lib/services/gen-api"; 3 | import { UsersService } from "$lib/services/gen-api"; 4 | import dayjs from "dayjs"; 5 | 6 | export const registerUser = async (user: RegisterUserDto): Promise => { 7 | const result = await UsersService.register({ 8 | requestBody: { 9 | email: user.email, 10 | fullName: user.fullName, 11 | password: user.password 12 | } 13 | }); 14 | 15 | return { 16 | createdAt: new Date(), 17 | id: result.id, 18 | email: result.email, 19 | fullName: result.fullName, 20 | profilePictureUrl: result.profilePictureUrl, 21 | verifiedAt: dayjs(result.verifiedAt).toDate() 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /console/src/lib/usecases/users/signInWithGoogle.ts: -------------------------------------------------------------------------------- 1 | import { env } from "$env/dynamic/public"; 2 | import GoogleAuthProvider from "$lib/services/oauth/providers/google"; 3 | import { signInWithRedirect } from "$lib/services/oauth/signInWithRedirect"; 4 | import { validateEnv } from "$lib/utils/validateEnv"; 5 | 6 | export const signInWithGoogle = async () => { 7 | const validatedEnv = validateEnv(env); 8 | 9 | if (!validatedEnv) { 10 | throw new Error("Environment validation error"); 11 | } 12 | 13 | await signInWithRedirect( 14 | new GoogleAuthProvider({ 15 | clientId: validatedEnv.PUBLIC_OAUTH_GOOGLE_CLIENT_ID, 16 | scopes: [ 17 | "https://www.googleapis.com/auth/userinfo.email", 18 | "https://www.googleapis.com/auth/userinfo.profile" 19 | ] 20 | }) 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /console/src/lib/utils/buildFrontendUrl.ts: -------------------------------------------------------------------------------- 1 | import { env } from "$env/dynamic/public"; 2 | import { validateEnv } from "$lib/utils/validateEnv"; 3 | const validatedEnv = validateEnv(env); 4 | 5 | if (!validatedEnv) { 6 | throw new Error("Invalid env"); 7 | } 8 | 9 | const { PUBLIC_AI_AGENT_DOMAIN } = validatedEnv; 10 | 11 | export const buildFrontendUrl = (projectSlug: string) => { 12 | const protocol = window?.location?.protocol ?? "https:"; 13 | return `${protocol}//${projectSlug}.${PUBLIC_AI_AGENT_DOMAIN}`; 14 | }; 15 | -------------------------------------------------------------------------------- /console/src/lib/utils/clickOutside.ts: -------------------------------------------------------------------------------- 1 | export const clickOutside = (node: Node, onEventFunction: () => void) => { 2 | const handleClick = (event: Event) => { 3 | const path = event.composedPath(); 4 | 5 | if (!path.includes(node)) { 6 | onEventFunction(); 7 | } 8 | }; 9 | 10 | document.addEventListener("click", handleClick); 11 | 12 | return { 13 | destroy() { 14 | document.removeEventListener("click", handleClick); 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /console/src/lib/utils/genStoreKey.ts: -------------------------------------------------------------------------------- 1 | export const genStoreKey = (storeName: string) => { 2 | return `agentlabs/client/${storeName}`; 3 | }; 4 | -------------------------------------------------------------------------------- /console/src/lib/utils/time.ts: -------------------------------------------------------------------------------- 1 | export const durationToHumanReadable = (lifetime: number): string => { 2 | const seconds = Math.floor(lifetime / 1000); 3 | const minutes = Math.floor(seconds / 60); 4 | const hours = Math.floor(minutes / 60); 5 | 6 | const secondsString = `${seconds % 60}s`; 7 | const minutesString = minutes > 0 ? `${minutes % 60}m ` : ""; 8 | const hoursString = hours > 0 ? `${hours}h ` : ""; 9 | 10 | return `${hoursString}${minutesString}${secondsString}`; 11 | }; 12 | -------------------------------------------------------------------------------- /console/src/lib/utils/toast.ts: -------------------------------------------------------------------------------- 1 | import { toast } from "@zerodevx/svelte-toast"; 2 | 3 | export const toastError = (message: string) => { 4 | toast.push(message, { 5 | theme: { 6 | "--toastBackground": "#ef434b", 7 | "--toastProgressBackground": "#ff7875" 8 | } 9 | }); 10 | }; 11 | 12 | export const toastSuccess = (message: string) => { 13 | toast.push(message, { 14 | theme: { 15 | "--toastBackground": "#00C48C", 16 | "--toastProgressBackground": "#95de64" 17 | } 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /console/src/lib/utils/unique.ts: -------------------------------------------------------------------------------- 1 | export const unique = (arr: T[]): T[] => { 2 | const set = new Set(arr); 3 | return Array.from(set); 4 | }; 5 | -------------------------------------------------------------------------------- /console/src/lib/utils/validateEnv.ts: -------------------------------------------------------------------------------- 1 | import z from "zod"; 2 | 3 | export const Environment = z.object({ 4 | PUBLIC_AI_AGENT_DOMAIN: z.string().min(1), 5 | PUBLIC_OAUTH_GOOGLE_CLIENT_ID: z.string().min(1), 6 | PUBLIC_TELEMETRY_KEY: z.string().optional(), 7 | PUBLIC_DISCORD_URL: z.string().optional(), 8 | PUBLIC_INTERCOM_APP_ID: z.string().optional(), 9 | }); 10 | 11 | export const validateEnv = (env: NodeJS.ProcessEnv) => { 12 | if (Object.keys(env).length === 0) { 13 | return null; 14 | } 15 | 16 | const parsed = Environment.safeParse(env); 17 | 18 | if (!parsed.success) { 19 | throw new Error(`Environment validation error: ${parsed.error}`); 20 | } 21 | 22 | return parsed.data; 23 | }; 24 | -------------------------------------------------------------------------------- /console/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | Home | AgentLabs 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /console/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /console/src/routes/login/+layout.svelte: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /console/src/routes/login/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import type { Load } from "@sveltejs/kit"; 3 | 4 | import { superValidate } from "sveltekit-superforms/server"; 5 | 6 | const schema = z.object({ 7 | email: z.string().email(), 8 | password: z.string().min(8) 9 | }); 10 | 11 | export const load: Load = async (event) => { 12 | const form = await superValidate(schema); 13 | return { 14 | form 15 | }; 16 | }; 17 | -------------------------------------------------------------------------------- /console/src/routes/logout/+page.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /console/src/routes/onboarding/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Get started | AgentLabs 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /console/src/routes/onboarding/new/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 7 |
    8 | 9 |
    10 |
    11 | -------------------------------------------------------------------------------- /console/src/routes/onboarding/new/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import type { Load } from "@sveltejs/kit"; 3 | 4 | import { superValidate } from "sveltekit-superforms/server"; 5 | 6 | const schema = z.object({ 7 | name: z.string() 8 | }); 9 | 10 | export const load: Load = async (event) => { 11 | const form = await superValidate(schema); 12 | return { 13 | form 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /console/src/routes/onboarding/project/[projectId]/+layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /console/src/routes/onboarding/project/[projectId]/ready/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 7 |
    8 | 9 |
    10 |
    11 | -------------------------------------------------------------------------------- /console/src/routes/project/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/+layout.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | Project | AgentLabs 11 | 12 | 13 | 14 |
    15 | 16 |
    17 | 18 |
    19 | 20 |
    21 |
    22 |
    23 |
    24 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/agent/[agentId]/+page.svelte: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/agent/new/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import type { Load } from "@sveltejs/kit"; 3 | 4 | import { superValidate } from "sveltekit-superforms/server"; 5 | 6 | const schema = z.object({ 7 | name: z.string() 8 | }); 9 | 10 | export const load: Load = async (event) => { 11 | const form = await superValidate(schema); 12 | return { 13 | form 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/auth/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/backends/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 7 |
    8 | Backends 10 |
    11 |
    12 | 13 |
    14 | -------------------------------------------------------------------------------- /console/src/routes/project/[projectId]/secrets/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | 7 |
    8 | Secrets 10 |
    11 |
    12 | 13 |
    14 | -------------------------------------------------------------------------------- /console/src/routes/project/overview/+page.svelte: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /console/src/routes/register/+layout.svelte: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /console/src/routes/register/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import type { Load } from "@sveltejs/kit"; 3 | 4 | import { superValidate } from "sveltekit-superforms/server"; 5 | 6 | const schema = z.object({ 7 | email: z.string().email(), 8 | password: z.string().min(8), 9 | name: z.string().min(2) 10 | }); 11 | 12 | export const load: Load = async (event) => { 13 | const form = await superValidate(schema); 14 | return { 15 | form 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /console/src/routes/types.ts: -------------------------------------------------------------------------------- 1 | export const SignInMethods = ["PASSWORDLESS_EMAIL", "GOOGLE"] as const; 2 | export type SignInMethod = (typeof SignInMethods)[number]; 3 | 4 | export type MainLayoutContext = { 5 | lazy: { 6 | context: Promise<{ 7 | tenantName: string; 8 | allowedSignInMethods: SignInMethod[]; 9 | }>; 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /console/static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /console/static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /console/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/apple-touch-icon.png -------------------------------------------------------------------------------- /console/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/favicon-16x16.png -------------------------------------------------------------------------------- /console/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/favicon.ico -------------------------------------------------------------------------------- /console/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/console/static/favicon.png -------------------------------------------------------------------------------- /console/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-node"; 2 | import { vitePreprocess } from "@sveltejs/kit/vite"; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | kit: { 10 | paths: { 11 | base: "/admin" 12 | }, 13 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 14 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 15 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 16 | adapter: adapter() 17 | } 18 | }; 19 | 20 | export default config; 21 | -------------------------------------------------------------------------------- /console/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /console/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from "@sveltejs/kit/vite"; 2 | import { defineConfig } from "vitest/config"; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ["src/**/*.{test,spec}.{js,ts}"] 8 | }, 9 | ssr: { 10 | noExternal: ["svelte-hero-icons"] 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | .git 4 | .gitignore 5 | .gitattributes 6 | README.md 7 | .npmrc 8 | .prettierrc 9 | .eslintrc.cjs 10 | .graphqlrc 11 | .editorconfig 12 | .svelte-kit 13 | .vscode 14 | node_modules 15 | build 16 | package 17 | **/.env 18 | -------------------------------------------------------------------------------- /frontend/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: [ 4 | "eslint:recommended", 5 | "plugin:typescript-eslint/recommended", 6 | "plugin:svelte/recommended", 7 | "prettier", 8 | "plugin:storybook/recommended", 9 | "plugin:storybook/recommended" 10 | ], 11 | parser: '@typescript-eslint/parser', 12 | plugins: ['@typescript-eslint'], 13 | parserOptions: { 14 | sourceType: 'module', 15 | ecmaVersion: 2020, 16 | extraFileExtensions: ['.svelte'] 17 | }, 18 | env: { 19 | browser: true, 20 | es2017: true, 21 | node: true 22 | }, 23 | overrides: [ 24 | { 25 | files: ['*.svelte'], 26 | parser: 'svelte-eslint-parser', 27 | parserOptions: { 28 | parser: '@typescript-eslint/parser' 29 | } 30 | } 31 | ] 32 | }; 33 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /frontend/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /frontend/.idea/agent-ui.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /frontend/.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /frontend/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/.idea/prettier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /frontend/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "trailingComma": "none", 4 | "tabWidth": 4, 5 | "printWidth": 100, 6 | "semi": true, 7 | "singleQuote": false, 8 | "jsxBracketSameLine": true, 9 | "overrides": [ { 10 | "files": "*.svelte", 11 | "options": { 12 | "svelteBracketNewLine": false, 13 | "svelteAllowShorthand": false, 14 | "svelteSortOrder" : "options-scripts-styles-markup", 15 | "plugins": [ "prettier-plugin-svelte" ] 16 | } 17 | } ], 18 | "pluginSearchDirs": [ "." ], 19 | "plugins": ["prettier-plugin-organize-imports"] 20 | } -------------------------------------------------------------------------------- /frontend/.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from "@storybook/sveltekit"; 2 | 3 | const config: StorybookConfig = { 4 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx|svelte)"], 5 | addons: [ 6 | "@storybook/addon-svelte-csf", 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials", 9 | "@storybook/addon-interactions", 10 | { 11 | name: "@storybook/addon-styling", 12 | options: {} 13 | } 14 | ], 15 | framework: { 16 | name: "@storybook/sveltekit", 17 | options: {} 18 | }, 19 | docs: { 20 | autodocs: "tag" 21 | } 22 | }; 23 | export default config; 24 | -------------------------------------------------------------------------------- /frontend/.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from "@storybook/svelte"; 2 | 3 | import { withThemeByClassName } from "@storybook/addon-styling"; 4 | 5 | import "../src/app.css"; 6 | 7 | const preview: Preview = { 8 | parameters: { 9 | actions: { argTypesRegex: "^on[A-Z].*" }, 10 | controls: { 11 | matchers: { 12 | color: /(background|color)$/i, 13 | date: /Date$/ 14 | } 15 | } 16 | }, 17 | 18 | decorators: [ 19 | // Adds theme switching support. 20 | // NOTE: requires setting "darkMode" to "class" in your tailwind config 21 | withThemeByClassName({ 22 | themes: { 23 | light: "light", 24 | dark: "dark" 25 | }, 26 | defaultTheme: "light" 27 | }) 28 | ] 29 | }; 30 | 31 | export default preview; 32 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as build-stage 2 | 3 | WORKDIR /app 4 | 5 | COPY package*.json . 6 | 7 | RUN npm ci 8 | 9 | COPY . . 10 | 11 | RUN npm run check 12 | 13 | RUN npm run build 14 | 15 | RUN npm prune --production 16 | 17 | FROM node:20-alpine3.17 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=build-stage /app/build build/ 22 | COPY --from=build-stage /app/node_modules node_modules/ 23 | COPY package.json . 24 | 25 | ENV NODE_ENV=production 26 | 27 | 28 | CMD [ "sh", "-c", "node -r dotenv/config build" ] 29 | -------------------------------------------------------------------------------- /frontend/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 2 | 3 | WORKDIR /app 4 | 5 | VOLUME [ "/app" ] 6 | 7 | # IMPORTANT: 8 | # As svelte kit uses vite under the hood, which itself use esbuild, it is necessary to install the deps from inside 9 | # the container as esbuild is a native dependency and it needs to be compiled for the target platform. 10 | 11 | ENTRYPOINT [ "sh", "-c", "npm install && npm run dev -- --port 3000 --host" ] 12 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /frontend/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | } 11 | 12 | export {}; 13 | -------------------------------------------------------------------------------- /frontend/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %sveltekit.head% 9 | 10 | 11 |
    %sveltekit.body%
    12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/src/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest'; 2 | 3 | describe('sum test', () => { 4 | it('adds 1 + 2 to equal 3', () => { 5 | expect(1 + 2).toBe(3); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /frontend/src/lib/assets/img/agent-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/src/lib/assets/img/gitlab-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/lib/assets/img/google-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/lib/assets/img/microsoft-icon.svg: -------------------------------------------------------------------------------- 1 | MS-SymbolLockup -------------------------------------------------------------------------------- /frontend/src/lib/components/auth/GithubIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"github"} 6 | -------------------------------------------------------------------------------- /frontend/src/lib/components/auth/GitlabIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"gitlab"} 6 | -------------------------------------------------------------------------------- /frontend/src/lib/components/auth/GoogleIcon.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {"google"} 6 | -------------------------------------------------------------------------------- /frontend/src/lib/components/auth/types.ts: -------------------------------------------------------------------------------- 1 | export const AuthProviders = [ 2 | "PASSWORDLESS_EMAIL", 3 | "EMAIL_AND_PASSWORD", 4 | "SMS", 5 | "ANONYMOUS", 6 | "GOOGLE", 7 | "GITHUB", 8 | "GITLAB", 9 | "MICROSOFT" 10 | ] as const; 11 | export type AuthProvider = (typeof AuthProviders)[number]; 12 | 13 | export const AuthProviderNameMap: Record = { 14 | GOOGLE: "Google", 15 | GITHUB: "GitHub", 16 | GITLAB: "GitLab", 17 | PASSWORDLESS_EMAIL: "Passwordless email", 18 | EMAIL_AND_PASSWORD: "Email and password", 19 | SMS: "SMS", 20 | ANONYMOUS: "Anonymous", 21 | MICROSOFT: "Microsoft" 22 | } as const; 23 | -------------------------------------------------------------------------------- /frontend/src/lib/components/chat/chat-message/SelectMessage/multi-select/types.ts: -------------------------------------------------------------------------------- 1 | import type { IconSource } from "svelte-hero-icons"; 2 | 3 | export type MultiSelectChoice = { 4 | id: string; 5 | label: string; 6 | value: string; 7 | heroIcon?: IconSource; 8 | disabled?: boolean; 9 | disabledLabel?: string; 10 | selected?: boolean; 11 | required?: boolean; 12 | }; 13 | -------------------------------------------------------------------------------- /frontend/src/lib/components/chat/chat-message/TypingLoader.svelte: -------------------------------------------------------------------------------- 1 |
    3 |
    4 |
    5 |
    6 |
    7 | -------------------------------------------------------------------------------- /frontend/src/lib/components/chat/processing-status/ProcessingStatus.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/svelte"; 2 | 3 | import ProcessingStatus from "./ProcessingStatus.svelte"; 4 | 5 | // More on how to set up stories at: https://storybook.js.org/docs/svelte/writing-stories/introduction 6 | const meta = { 7 | title: "Chat/ProcessingStatus", 8 | component: ProcessingStatus, 9 | tags: ["autodocs"] 10 | } satisfies Meta; 11 | 12 | export default meta; 13 | type Story = StoryObj; 14 | 15 | // More on writing stories with args: https://storybook.js.org/docs/svelte/writing-stories/args 16 | export const Default: Story = { 17 | args: { 18 | content: "Finding a way to proceed..." 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /frontend/src/lib/components/chat/processing-status/ProcessingStatus.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
    6 | {content} 7 |
    8 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/avatar/Avatar.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/svelte"; 2 | 3 | import Avatar from "./Avatar.svelte"; 4 | 5 | // More on how to set up stories at: https://storybook.js.org/docs/svelte/writing-stories/introduction 6 | const meta = { 7 | title: "Common/Avatar", 8 | component: Avatar, 9 | tags: ["autodocs"] 10 | } satisfies Meta; 11 | 12 | export default meta; 13 | type Story = StoryObj; 14 | 15 | // More on writing stories with args: https://storybook.js.org/docs/svelte/writing-stories/args 16 | export const Basic: Story = { 17 | args: { 18 | alt: "Some user profile image", 19 | src: "https://media.licdn.com/dms/image/D4E03AQFXJiFpNFWE0A/profile-displayphoto-shrink_100_100/0/1680893451739?e=1699488000&v=beta&t=WiNliB67TjMHbaIycm8u55JDrX82xu9I20jw-b10u4A" 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/avatar/Avatar.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 |
    13 | {#if image.src} 14 | { 17 | image.src = null; 18 | }} 19 | alt={alt} 20 | class="rounded-full w-9" /> 21 | {:else} 22 |
    24 | 28 |
    29 | {/if} 30 |
    31 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/button/button.types.ts: -------------------------------------------------------------------------------- 1 | export const ButtonStatuses = ["disabled", "loading", "default"]; 2 | export type ButtonStatus = (typeof ButtonStatuses)[number]; 3 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/card/Card.stories.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/card/Card.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
    {}} 20 | class="{clickableClass} w-full rounded-2xl border border-stroke-base dark:border-stroke-base-dark bg-background-tertiary dark:bg-background-tertiary-dark"> 21 | 22 |
    23 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/card/CardBody.svelte: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/card/CardSkeleton.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |
    7 |
    9 |
    11 |
    13 |
    14 | 15 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/letter-avatar/LetterAvatar.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 |
    6 | 7 |
    8 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/loading-frame/LoadingFrame.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
    17 |
    18 | 19 |
    20 |
    21 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/logo/AgentLabsLogo.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | AgentLabs Logo 9 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/logo/PoweredBy.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 | Powered by AgentLabs.dev 7 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/navigation/nav-item/NavItem.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
  • {}} 14 | on:click={() => goto(item.path)} 15 | class="{isActive ? 'bg-background-accent dark:bg-background-accent-dark' : ''} 16 | hover:bg-background-accent dark:hover:bg-background-accent-dark text-sm text-body-base dark:text-body-base-dark py-3 px-4 rounded-lg flex gap-2 items-center cursor-pointer"> 17 | {#if item?.icon} 18 | 19 | {/if} 20 | {item.label} 21 |
  • 22 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/navigation/nav-item/types.ts: -------------------------------------------------------------------------------- 1 | import type { IconSource } from "svelte-hero-icons"; 2 | 3 | export type NavItemType = { 4 | path: string; 5 | label: string; 6 | icon?: IconSource; 7 | }; 8 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/navigation/tab-nav/types.ts: -------------------------------------------------------------------------------- 1 | export type TabNavItem = { 2 | path: string; 3 | label: string; 4 | }; 5 | -------------------------------------------------------------------------------- /frontend/src/lib/components/common/spacer/Spacer.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    14 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-image.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {token.text} 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-link.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-list-item.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 |
  • 12 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-list.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | {#each token.items as item} 15 | 16 | {/each} 17 | 18 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-paragraph.svelte: -------------------------------------------------------------------------------- 1 | 3 | 4 |

    5 | 6 |

    7 | -------------------------------------------------------------------------------- /frontend/src/lib/components/markdown/markdown-renderer.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 26 | -------------------------------------------------------------------------------- /frontend/src/lib/components/sidebar/Sidebar.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    8 |
    9 | 10 |
    11 |
    12 | -------------------------------------------------------------------------------- /frontend/src/lib/components/sidebar/header/SidebarHeader.svelte: -------------------------------------------------------------------------------- 1 |
    2 | 4 | 5 |
    6 | -------------------------------------------------------------------------------- /frontend/src/lib/context/AgentContext.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | {#if loading} 23 | 24 | {:else} 25 | 26 | {/if} 27 | -------------------------------------------------------------------------------- /frontend/src/lib/context/RealtimeContext.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 | {#if isLoading} 29 | 30 | {:else} 31 | 32 | {/if} 33 | -------------------------------------------------------------------------------- /frontend/src/lib/entities/agent/agent.ts: -------------------------------------------------------------------------------- 1 | export interface Agent { 2 | id: string; 3 | name: string; 4 | createdAt: string; 5 | updatedAt: string; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/lib/entities/conversation/conversation.ts: -------------------------------------------------------------------------------- 1 | import type { ConversationMessage } from "../message/message"; 2 | 3 | export interface Conversation { 4 | id: string; 5 | createdAt: string; 6 | updatedAt: string; 7 | 8 | projectId: string; 9 | memberId: string; 10 | } 11 | 12 | export interface ConversationWithMessages extends Conversation { 13 | messages: ConversationMessage[]; 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/lib/entities/member/member.ts: -------------------------------------------------------------------------------- 1 | export type Member = { 2 | id: string; 3 | fullName: string | null; 4 | firstName: string | null; 5 | lastName: string | null; 6 | profilePictureUrl: string | null; 7 | isAnonymous: boolean; 8 | verifiedAt: Date | null; 9 | email: string | null; 10 | createdAt: Date; 11 | updatedAt: Date; 12 | }; 13 | -------------------------------------------------------------------------------- /frontend/src/lib/entities/message/message.ts: -------------------------------------------------------------------------------- 1 | export type Message = { 2 | id: string; 3 | text: string; 4 | createdAt: Date; 5 | senderFullName: string; 6 | senderId: string; 7 | from: "user" | "agent"; 8 | }; 9 | 10 | export const AgentMessageSources = [ 11 | 'USER', 12 | 'AGENT', 13 | 'SYSTEM' 14 | ] 15 | 16 | export type AgentMessageSource = typeof AgentMessageSources[number] 17 | 18 | export interface MessageAttachmentWrapper { 19 | attachment: MessageAttachment; 20 | } 21 | 22 | export interface MessageAttachment { 23 | id: string; 24 | createdAt: string; 25 | updatedAt: string; 26 | name: string; 27 | mimeType: string; 28 | sizeBytes: number; 29 | } 30 | 31 | export interface ConversationMessage { 32 | id: string; 33 | createdAt: string; 34 | updateAt: string; 35 | 36 | source: AgentMessageSource; 37 | text: string; 38 | 39 | conversationId: string; 40 | 41 | attachments: MessageAttachmentWrapper[]; 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/lib/entities/project/public-project-config.ts: -------------------------------------------------------------------------------- 1 | export interface PublicProjectConfig { 2 | id: string; 3 | slug: string; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /frontend/src/lib/routes/routes.ts: -------------------------------------------------------------------------------- 1 | const basePath = ""; 2 | 3 | export const homeRoute = { 4 | path: () => `${basePath}/chat` 5 | }; 6 | 7 | export const agentChatRoute = { 8 | path: () => `${basePath}/chat` 9 | }; 10 | 11 | export const chatConversationRoute = { 12 | path: (conversationId: string) => `${basePath}/chat/c/${conversationId}` 13 | }; 14 | 15 | export const logoutRoute = { 16 | path: () => `${basePath}/logout` 17 | }; 18 | 19 | export const verifyPasswordlessEmailRoute = { 20 | path: (email: string) => `${basePath}/register/verify?email=${email}` 21 | }; 22 | 23 | export const projectNotFoundRoute = { 24 | path: () => `${basePath}/project-not-found` 25 | }; 26 | -------------------------------------------------------------------------------- /frontend/src/lib/services/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/src/lib/services/.gitkeep -------------------------------------------------------------------------------- /frontend/src/lib/services/oauth/codeVerifier.ts: -------------------------------------------------------------------------------- 1 | const CODE_VERIFIER_SESSION_KEY = "agentlabs/console/oauth/code-verifier"; 2 | 3 | export const saveCodeVerifier = (codeVerifier: string): void => { 4 | sessionStorage.setItem(CODE_VERIFIER_SESSION_KEY, codeVerifier); 5 | }; 6 | 7 | export const getCodeVerifier = (): string | null => { 8 | return sessionStorage.getItem(CODE_VERIFIER_SESSION_KEY); 9 | }; 10 | -------------------------------------------------------------------------------- /frontend/src/lib/services/oauth/randomState.ts: -------------------------------------------------------------------------------- 1 | export const randomState = (length = 40) => { 2 | const crypto = window.crypto; 3 | const validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 4 | const array = new Uint8Array(length); 5 | crypto.getRandomValues(array); 6 | const values = new Array(length); 7 | array.forEach((v, i) => { 8 | values[i] = validChars.charCodeAt(v % validChars.length); 9 | }); 10 | return String.fromCharCode.apply(null, values); 11 | }; 12 | -------------------------------------------------------------------------------- /frontend/src/lib/store/chat/chat.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | function createChat() { 4 | const { subscribe, set, update } = writable(0); 5 | 6 | return { 7 | subscribe, 8 | interrupt: () => { 9 | alert("Agent has been interrupted!"); 10 | }, 11 | continue: () => { 12 | alert("Human triggered continue."); 13 | }, 14 | activateContinuous: () => { 15 | alert("Continuous mode activated"); 16 | } 17 | }; 18 | } 19 | 20 | export const chat = createChat(); 21 | -------------------------------------------------------------------------------- /frontend/src/lib/stores/agent.ts: -------------------------------------------------------------------------------- 1 | import { get, writable } from "svelte/store"; 2 | import type { Agent } from "$lib/entities/agent/agent"; 3 | 4 | export type AgentStore = { 5 | list: Agent[]; 6 | }; 7 | 8 | export const agentStore = writable({ 9 | list: [], 10 | }); 11 | 12 | export const setSelectedAgent = (agent: Agent) => { 13 | agentStore.update((store) => { 14 | return { 15 | ...store, 16 | selectedAgent: agent 17 | }; 18 | }); 19 | }; 20 | 21 | export const setAvailableAgents = (agents: Agent[]) => { 22 | agentStore.update((store) => { 23 | return { 24 | ...store, 25 | list: agents 26 | }; 27 | }); 28 | }; 29 | 30 | export const getAgentById = (id: string) => { 31 | return get(agentStore).list.find((agent) => agent.id === id); 32 | } 33 | -------------------------------------------------------------------------------- /frontend/src/lib/stores/left-nav.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | 3 | export type LeftNavStore = { 4 | isOpened: boolean; 5 | toggle: () => void; 6 | close: () => void; 7 | }; 8 | 9 | export const leftNavStore = writable({ 10 | isOpened: true, 11 | close: () => { 12 | leftNavStore.update((theme) => { 13 | return { 14 | ...theme, 15 | isOpened: false 16 | }; 17 | }); 18 | }, 19 | toggle: () => { 20 | leftNavStore.update((theme) => { 21 | return { 22 | ...theme, 23 | isOpened: !theme.isOpened 24 | }; 25 | }); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /frontend/src/lib/stores/main-context.ts: -------------------------------------------------------------------------------- 1 | import type { PublicProjectConfigDto } from "$lib/services/gen-api"; 2 | import { get, writable } from "svelte/store"; 3 | 4 | export type MainContextStore = { 5 | publicProjectConfig: PublicProjectConfigDto | null; 6 | }; 7 | 8 | export const mainContextStore = writable({ 9 | publicProjectConfig: null 10 | }); 11 | 12 | export const setPublicProjectConfig = (value: PublicProjectConfigDto) => { 13 | mainContextStore.update((store) => { 14 | store.publicProjectConfig = value; 15 | return store; 16 | }); 17 | }; 18 | 19 | export const getMainContextStore = () => { 20 | return get(mainContextStore); 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /frontend/src/lib/stores/theme.ts: -------------------------------------------------------------------------------- 1 | import { genStoreKey } from "$lib/utils/genStoreKey"; 2 | import { createLocalStorage, persist } from "@macfja/svelte-persistent-store"; 3 | import { writable } from "svelte/store"; 4 | 5 | export type Theme = "light" | "dark"; 6 | 7 | const THEME_STORE_KEY = genStoreKey("theme-store"); 8 | 9 | export const themeStore = persist(writable("dark"), createLocalStorage(), THEME_STORE_KEY); 10 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/agents/fetch-agents.ts: -------------------------------------------------------------------------------- 1 | import type { Agent } from "$lib/entities/agent/agent"; 2 | import { AgentsService } from "$lib/services/gen-api"; 3 | import { setAvailableAgents } from "$lib/stores/agent"; 4 | 5 | export const fetchAgents = async (projectId: string): Promise => { 6 | const { items: agents } = await AgentsService.listForProject({ projectId }); 7 | 8 | setAvailableAgents(agents); 9 | 10 | return agents; 11 | }; 12 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/chat/fetch-messages.ts: -------------------------------------------------------------------------------- 1 | import { ChatMessagesService } from "$lib/services/gen-api" 2 | import { loadMessages } from "$lib/stores/chat" 3 | 4 | export const fetchMessages = async (conversationId: string) => { 5 | const messages = await ChatMessagesService.listByConversationId({ conversationId }) 6 | 7 | loadMessages(messages) 8 | 9 | return messages 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/conversations/fetch-conversations.ts: -------------------------------------------------------------------------------- 1 | import type { Conversation } from "$lib/entities/conversation/conversation"; 2 | import { ConversationsService } from "$lib/services/gen-api"; 3 | import { setConversationList } from "$lib/stores/conversation"; 4 | 5 | export const fetchConversations = async (projectId: string): Promise => { 6 | const conversations = await ConversationsService.getAllConversations({ 7 | projectId 8 | }); 9 | 10 | setConversationList(conversations); 11 | 12 | return conversations; 13 | }; 14 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/members/requestPasswordlessEmail.ts: -------------------------------------------------------------------------------- 1 | import type { RegisterResponseDto } from "$lib/services/gen-api"; 2 | import { MembersService } from "$lib/services/gen-api"; 3 | 4 | export const requestPasswordlessEmail = async (params: { 5 | projectId: string; 6 | email: string; 7 | }): Promise => { 8 | const { projectId, email } = params; 9 | 10 | const result = await MembersService.requestPasswordlessEmail({ 11 | projectId, 12 | requestBody: { 13 | email 14 | } 15 | }); 16 | 17 | return result; 18 | }; 19 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/members/verifyMemberOrLogout.ts: -------------------------------------------------------------------------------- 1 | import { goto } from "$app/navigation"; 2 | import { logoutRoute } from "$lib/routes/routes"; 3 | import { MembersService } from "$lib/services/gen-api"; 4 | 5 | export const verifyMemberOrLogout = async () => { 6 | try { 7 | const member = await MembersService.whoami(); 8 | } catch (e: any) { 9 | if (e.status === 401) { 10 | await goto(logoutRoute.path()); 11 | } else { 12 | console.error(e); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /frontend/src/lib/usecases/project/retrievePublicConfig.ts: -------------------------------------------------------------------------------- 1 | import { ProjectsService } from "$lib/services/gen-api"; 2 | import { setPublicProjectConfig } from "$lib/stores/main-context"; 3 | 4 | export const retrievePublicConfig = async (hostname: string) => { 5 | const config = await ProjectsService.getPublicConfig({ hostname }); 6 | 7 | setPublicProjectConfig(config); 8 | 9 | return config; 10 | }; 11 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/clickOutside.ts: -------------------------------------------------------------------------------- 1 | export const clickOutside = (node: Node, onEventFunction: () => void) => { 2 | const handleClick = (event: Event) => { 3 | const path = event.composedPath(); 4 | 5 | if (!path.includes(node)) { 6 | onEventFunction(); 7 | } 8 | }; 9 | 10 | document.addEventListener("click", handleClick); 11 | 12 | return { 13 | destroy() { 14 | document.removeEventListener("click", handleClick); 15 | } 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/genStoreKey.ts: -------------------------------------------------------------------------------- 1 | export const genStoreKey = (storeName: string) => { 2 | return `agentlabs/client/${storeName}`; 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/toast.ts: -------------------------------------------------------------------------------- 1 | import { toast } from "@zerodevx/svelte-toast"; 2 | 3 | export const toastError = (message: string) => { 4 | toast.push(message, { 5 | theme: { 6 | "--toastBackground": "#ef434b", 7 | "--toastProgressBackground": "#ff7875" 8 | } 9 | }); 10 | }; 11 | 12 | export const toastSuccess = (message: string) => { 13 | toast.push(message, { 14 | theme: { 15 | "--toastBackground": "#00C48C", 16 | "--toastProgressBackground": "#95de64" 17 | } 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/unique.ts: -------------------------------------------------------------------------------- 1 | export const unique = (arr: T[]): T[] => { 2 | const set = new Set(arr); 3 | return Array.from(set); 4 | }; 5 | -------------------------------------------------------------------------------- /frontend/src/lib/utils/validateEnv.ts: -------------------------------------------------------------------------------- 1 | import z from "zod"; 2 | 3 | export const Environment = z.object({ 4 | PUBLIC_APP_HOST: z.string().min(1) 5 | }); 6 | 7 | export const validateEnv = (env: NodeJS.ProcessEnv) => { 8 | if (Object.keys(env).length === 0) { 9 | return null; 10 | } 11 | 12 | const parsed = Environment.safeParse(env); 13 | 14 | if (!parsed.success) { 15 | throw new Error(`Environment validation error: ${parsed.error}`); 16 | } 17 | 18 | return parsed.data; 19 | }; 20 | -------------------------------------------------------------------------------- /frontend/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/src/routes/chat/+page.svelte: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /frontend/src/routes/chat/c/[conversationId]/+page.svelte: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /frontend/src/routes/logout/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /frontend/src/routes/types.ts: -------------------------------------------------------------------------------- 1 | export const SignInMethods = ["PASSWORDLESS_EMAIL", "GOOGLE"] as const; 2 | export type SignInMethod = (typeof SignInMethods)[number]; 3 | 4 | export type MainLayoutContext = { 5 | mainLayoutLazy: { 6 | isLoaded: Promise; 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/src/services/agents.types.ts: -------------------------------------------------------------------------------- 1 | export interface AgentInfo { 2 | id: string 3 | logoUrl: string | null; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /frontend/static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /frontend/static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/apple-touch-icon.png -------------------------------------------------------------------------------- /frontend/static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/favicon-16x16.png -------------------------------------------------------------------------------- /frontend/static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/favicon-32x32.png -------------------------------------------------------------------------------- /frontend/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/favicon.ico -------------------------------------------------------------------------------- /frontend/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/frontend/static/favicon.png -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from "@sveltejs/adapter-node"; 2 | import { vitePreprocess } from "@sveltejs/kit/vite"; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from "@sveltejs/kit/vite"; 2 | import { defineConfig } from "vitest/config"; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()], 6 | test: { 7 | include: ["src/**/*.{test,spec}.{js,ts}"] 8 | }, 9 | ssr: { 10 | noExternal: ["svelte-hero-icons", "marked"] 11 | }, 12 | server: {}, 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /scripts/frontend-clients/.gitignore: -------------------------------------------------------------------------------- 1 | src 2 | -------------------------------------------------------------------------------- /scripts/frontend-clients/build_for_console.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | echo "🚀 Generating typescript client for console..." 6 | 7 | npx --yes openapi-typescript-codegen \ 8 | --input ../../server/openapi.yaml \ 9 | --output ./src \ 10 | --useOptions \ 11 | --useUnionTypes 12 | 13 | cp client.ts src/ 14 | 15 | OPENAPI_BASE=${OPENAPI_BASE:-http://localhost:3001} 16 | 17 | echo 'Setting environment variables for OpenAPI_BASE:' ${OPENAPI_BASE} 18 | echo "OpenAPI.BASE = '${OPENAPI_BASE}';" >> src/client.ts 19 | 20 | echo 'export { getToken } from "./client";' >> src/index.ts 21 | 22 | rm -rf ../../console/src/lib/services/gen-api 23 | # important: gen-api folder must be in .gitignore since we don't want to commit it. 24 | cp -R ./src ../../console/src/lib/services/gen-api 25 | 26 | echo -e "✅ Done!\n" 27 | -------------------------------------------------------------------------------- /scripts/frontend-clients/build_for_frontend.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | echo "🚀 Generating typescript client for console..." 6 | 7 | npx --yes openapi-typescript-codegen \ 8 | --input ../../server/openapi.yaml \ 9 | --output ./src \ 10 | --useOptions \ 11 | --useUnionTypes 12 | 13 | cp client.ts src/ 14 | 15 | OPENAPI_BASE=${OPENAPI_BASE:-http://localhost:3001} 16 | 17 | echo 'Setting environment variables for OpenAPI_BASE:' ${OPENAPI_BASE} 18 | echo "OpenAPI.BASE = '${OPENAPI_BASE}';" >> src/client.ts 19 | 20 | echo 'export { getToken } from "./client";' >> src/index.ts 21 | 22 | rm -rf ../../frontend/src/lib/services/gen-api 23 | # important: gen-api folder must be in .gitignore since we don't want to commit it. 24 | cp -R ./src ../../frontend/src/lib/services/gen-api 25 | 26 | echo -e "✅ Done!\n" 27 | -------------------------------------------------------------------------------- /scripts/frontend-clients/client.ts: -------------------------------------------------------------------------------- 1 | import { OpenAPI } from "./index"; 2 | import { getAccessTokenPromise } from "$lib/stores/auth"; 3 | 4 | /* We can overwrite the default configuration by exporting a getToken function. 5 | * This function will be called before each request to get a token. 6 | * See: https://github.com/ferdikoomen/openapi-typescript-codegen/blob/master/docs/authorization.md 7 | */ 8 | export const getToken = async () => { 9 | return await getAccessTokenPromise(); 10 | }; 11 | 12 | OpenAPI.TOKEN = getToken; 13 | -------------------------------------------------------------------------------- /sdks/node-sdk/.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /sdks/node-sdk/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution'); 3 | 4 | module.exports = { 5 | root: true, 6 | extends: [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/eslint-config-typescript', 10 | '@vue/eslint-config-prettier', 11 | ], 12 | parserOptions: { 13 | ecmaVersion: 'latest', 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /sdks/node-sdk/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .idea 4 | *tgz 5 | -------------------------------------------------------------------------------- /sdks/node-sdk/.npmrc: -------------------------------------------------------------------------------- 1 | //registry.npmjs.org/:_authToken=${NPM_TOKEN} 2 | -------------------------------------------------------------------------------- /sdks/node-sdk/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "arrowParens": "always", 5 | "tabWidth": 4, 6 | "useTabs": false, 7 | "bracketSpacing": true 8 | } -------------------------------------------------------------------------------- /sdks/node-sdk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY . . 6 | 7 | COPY .npmrc /root/.npmrc 8 | 9 | COPY scripts/docker-entrypoint.sh /entrypoint.sh 10 | 11 | CMD [ "sh", "/entrypoint.sh" ] 12 | -------------------------------------------------------------------------------- /sdks/node-sdk/scripts/build.js: -------------------------------------------------------------------------------- 1 | const esbuild = require('esbuild'); 2 | const packageJson = require('../package.json'); 3 | const { join } = require('path'); 4 | 5 | console.time('done in'); 6 | console.log('Building package... 👨‍🍳'); 7 | 8 | esbuild.buildSync({ 9 | entryPoints: [join(__dirname, '..', 'src', 'index.ts')], 10 | outfile: join(__dirname, '..', 'dist', 'index.js'), 11 | bundle: true, 12 | target: ['esnext'], 13 | platform: 'node', 14 | minify: false, 15 | external: [ 16 | ...Object.keys(packageJson.dependencies ?? []), 17 | ...Object.keys(packageJson.peerDependencies ?? []), 18 | ], 19 | }); 20 | 21 | console.timeEnd('done in'); 22 | -------------------------------------------------------------------------------- /sdks/node-sdk/scripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | validate_env() { 6 | if [ -z "$NPM_TOKEN" ]; then 7 | echo "NPM_TOKEN is not set, exiting" 8 | exit 1 9 | fi 10 | } 11 | 12 | prepare_config() { 13 | sed -i "s/\"version\": \".*\"/\"version\": \"$VERSION\"/g" package.json 14 | echo "Configured package.json version to $VERSION" 15 | } 16 | 17 | validate_env 18 | 19 | if [ -z "$VERSION" ]; then 20 | echo "VERSION is not set, skipping package.json configuration" 21 | exit 1 22 | else 23 | prepare_config 24 | fi 25 | 26 | npm ci 27 | npm run build 28 | 29 | npm publish --access public 30 | -------------------------------------------------------------------------------- /sdks/node-sdk/src/const.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_INITIAL_MESSAGE_LOADING_DELAY_MS = 1500; 2 | export const DEFAULT_MESSAGE_TYPING_INTERVAL_MS = 60; 3 | 4 | export const DEFAULT_STREAM_TOKEN_SIZE = 3; 5 | -------------------------------------------------------------------------------- /sdks/node-sdk/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { MessageFormat } from "./types"; 2 | 3 | export const localMessageFormatToRemote: Record = { 4 | PlainText: 'PLAIN_TEXT', 5 | Markdown: 'MARKDOWN', 6 | } 7 | -------------------------------------------------------------------------------- /sdks/node-sdk/src/incoming-chat-message.ts: -------------------------------------------------------------------------------- 1 | import { MessageAttachment } from './message-attachment'; 2 | import { Member, RawChatMessage } from './types'; 3 | import { HttpApi } from './http'; 4 | 5 | export class IncomingChatMessage { 6 | public readonly text: string; 7 | public readonly conversationId: string; 8 | public readonly messageId: string; 9 | public readonly memberId: string; 10 | public readonly member: Member; 11 | public readonly attachments: MessageAttachment[]; 12 | 13 | constructor(http: HttpApi, message: RawChatMessage) { 14 | this.text = message.text; 15 | this.conversationId = message.conversationId; 16 | this.messageId = message.messageId; 17 | this.memberId = message.member.id; 18 | this.member = message.member; 19 | this.attachments = (message.attachments ?? []).map((a) => new MessageAttachment(http, a)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /sdks/node-sdk/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './agent'; 2 | export * from './project'; 3 | export * from './types'; 4 | export * from './attachment' 5 | -------------------------------------------------------------------------------- /sdks/node-sdk/src/utils/chunk.ts: -------------------------------------------------------------------------------- 1 | export const chunk = (text: string, size: number) => { 2 | const length = text == null ? 0 : text.length; 3 | if (!length || size < 1) { 4 | return []; 5 | } 6 | let index = 0; 7 | let resIndex = 0; 8 | const result = new Array(Math.ceil(length / size)); 9 | 10 | while (index < length) { 11 | result[resIndex++] = text.slice(index, (index += size)); 12 | } 13 | return result; 14 | }; 15 | -------------------------------------------------------------------------------- /sdks/python-sdk/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /sdks/python-sdk/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12.0-alpine3.18 2 | 3 | RUN apk add --no-cache \ 4 | curl \ 5 | poetry 6 | 7 | ENV PATH="${PATH}:/root/.local/bin" 8 | 9 | COPY . . 10 | 11 | COPY ./scripts/docker-entrypoint.sh /entrypoint.sh 12 | 13 | ENTRYPOINT ["sh", "/entrypoint.sh"] 14 | -------------------------------------------------------------------------------- /sdks/python-sdk/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/sdks/python-sdk/README.md -------------------------------------------------------------------------------- /sdks/python-sdk/agentlabs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/sdks/python-sdk/agentlabs/__init__.py -------------------------------------------------------------------------------- /sdks/python-sdk/agentlabs/_internals/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/sdks/python-sdk/agentlabs/_internals/__init__.py -------------------------------------------------------------------------------- /sdks/python-sdk/agentlabs/_internals/const.py: -------------------------------------------------------------------------------- 1 | DEFAULT_INITIAL_MESSAGE_LOADING_DELAY_MS = 1500 2 | DEFAULT_MESSAGE_TYPING_INTERVAL_MS = 60 3 | DEFAULT_STREAM_TOKEN_SIZE = 3 4 | -------------------------------------------------------------------------------- /sdks/python-sdk/agentlabs/_internals/logger.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | class Logger: 4 | def __init__(self, name: str) -> None: 5 | self.name = name 6 | 7 | def _format_log(self, level: str, message: str) -> str: 8 | return f"[{self.name}] {datetime.now().strftime('%m/%d/%Y, %H:%M:%S')} {level} {message}" 9 | 10 | def _log(self, level: str, message: str) -> None: 11 | print(self._format_log(level, message)) 12 | 13 | def info(self, message: str) -> None: 14 | self._log("INFO", message) 15 | 16 | def warn(self, message: str) -> None: 17 | self._log("WARN", message) 18 | 19 | def error(self, message: str) -> None: 20 | self._log("ERROR", message) 21 | 22 | def debug(self, message: str) -> None: 23 | self._log("DEBUG", message) 24 | -------------------------------------------------------------------------------- /sdks/python-sdk/agentlabs/_internals/utils.py: -------------------------------------------------------------------------------- 1 | def chunk_str(input_string, chunk_size): 2 | return [input_string[i:i + chunk_size] for i in range(0, len(input_string), chunk_size)] 3 | -------------------------------------------------------------------------------- /sdks/python-sdk/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "agentlabs-sdk" 3 | version = "0.0.0" 4 | description = "AgentLabs SDK for Python" 5 | authors = ["Aurélien Brabant "] 6 | readme = "README.md" 7 | packages = [ 8 | { include = "agentlabs" } 9 | ] 10 | 11 | [tool.poetry.dependencies] 12 | python = ">=3.9" 13 | websocket-client = "^1.6.3" 14 | python-socketio = "^5.9.0" 15 | requests = "^2.31.0" 16 | 17 | [build-system] 18 | requires = ["poetry-core"] 19 | build-backend = "poetry.core.masonry.api" 20 | -------------------------------------------------------------------------------- /sdks/python-sdk/scripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | validate_env() { 6 | if [ -z "$PYPI_TOKEN" ]; then 7 | echo "PYPI_TOKEN env var is not set, exiting" 8 | exit 1 9 | fi 10 | } 11 | 12 | prepare_config() { 13 | sed -i "s/^version = .*$/version = \"$VERSION\"/" pyproject.toml 14 | echo "Wrote version to pyproject.toml ($VERSION)" 15 | } 16 | 17 | validate_env 18 | 19 | if [ -z "$VERSION" ]; then 20 | echo "VERSION env var is not set, will use pyproject.toml version unmodified." 21 | else 22 | prepare_config 23 | fi 24 | 25 | poetry config pypi-token.pypi "$PYPI_TOKEN" 26 | 27 | poetry publish --build \ 28 | --no-interaction \ 29 | --build 30 | -------------------------------------------------------------------------------- /sdks/python-sdk/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/sdks/python-sdk/tests/__init__.py -------------------------------------------------------------------------------- /server/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .git 3 | dist 4 | Dockerfile 5 | .dockerignore 6 | test 7 | README.md 8 | -------------------------------------------------------------------------------- /server/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module', 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin'], 9 | extends: [ 10 | 'plugin:@typescript-eslint/recommended', 11 | 'plugin:prettier/recommended', 12 | ], 13 | root: true, 14 | env: { 15 | node: true, 16 | jest: true, 17 | }, 18 | ignorePatterns: ['.eslintrc.js'], 19 | rules: { 20 | '@typescript-eslint/interface-name-prefix': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | '@typescript-eslint/explicit-module-boundary-types': 'off', 23 | '@typescript-eslint/no-explicit-any': 'off', 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | /attachments 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | pnpm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # OS 16 | .DS_Store 17 | 18 | # Tests 19 | /coverage 20 | /.nyc_output 21 | 22 | # IDEs and editors 23 | /.idea 24 | .project 25 | .classpath 26 | .c9/ 27 | *.launch 28 | .settings/ 29 | *.sublime-workspace 30 | 31 | # IDE - VSCode 32 | .vscode/* 33 | !.vscode/settings.json 34 | !.vscode/tasks.json 35 | !.vscode/launch.json 36 | !.vscode/extensions.json 37 | -------------------------------------------------------------------------------- /server/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json package-lock.json ./ 6 | 7 | RUN npm ci 8 | 9 | COPY . . 10 | 11 | RUN npx prisma generate 12 | 13 | RUN npm run build 14 | 15 | RUN npm prune --production 16 | 17 | FROM node:20-alpine3.17 as release 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=build /app/dist ./dist 22 | COPY --from=build /app/node_modules ./node_modules 23 | COPY --from=build /app/package.json ./package.json 24 | COPY --from=build /app/prisma ./prisma 25 | 26 | COPY --from=build /app/scripts/docker-entrypoint.sh docker-entrypoint.sh 27 | 28 | ENTRYPOINT [ "sh", "docker-entrypoint.sh" ] 29 | -------------------------------------------------------------------------------- /server/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as dev 2 | 3 | WORKDIR /app 4 | 5 | VOLUME [ "/app" ] 6 | 7 | COPY ./scripts/docker-entrypoint.dev.sh /docker-entrypoint.dev.sh 8 | 9 | ENTRYPOINT [ "sh", "/docker-entrypoint.dev.sh" ] 10 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # server 2 | 3 | A server that for now manages everything. 4 | 5 | ## Development 6 | 7 | ### Migrations 8 | 9 | **Important**: if required to work with migrations manually, you must do so inside the docker container where proper environment variables are set. Otherwise you'll run into issues to connect to the database. 10 | 11 | As long as the project is in its POC state we want to continuously allow ourselves to edit the initial migration file and not create many of them. 12 | We will start proper versioning once the first public release airs. 13 | 14 | To regenerate the initial migration file, run the following command. 15 | (If destructive schema operations were introduced, prisma will ask to wipe the schema and you will thus loose data) 16 | 17 | ``` 18 | npm run poc:regenerate-migrations 19 | ``` 20 | -------------------------------------------------------------------------------- /server/nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "assets": [ 7 | { "include": "**/*.hbs", "watchAssets": true } 8 | ], 9 | "deleteOutDir": true, 10 | "plugins": [ 11 | { 12 | "name": "@nestjs/swagger", 13 | "options": { 14 | "classValidatorShim": true, 15 | "introspectComments": false 16 | } 17 | } 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/openapitools.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", 3 | "spaces": 2, 4 | "generator-cli": { 5 | "version": "7.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/print-oas.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine3.17 as build 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json package-lock.json ./ 6 | 7 | RUN npm ci 8 | 9 | COPY . . 10 | 11 | RUN npx prisma generate 12 | 13 | RUN npm run build 14 | 15 | RUN npm prune --production 16 | 17 | FROM node:20-alpine3.17 as release 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=build /app/dist ./dist 22 | COPY --from=build /app/node_modules ./node_modules 23 | COPY --from=build /app/package.json ./package.json 24 | COPY --from=build /app/prisma ./prisma 25 | 26 | # we do use the special print-oas-docker-entrypoint.sh script here 27 | COPY --from=build /app/scripts/print-oas-docker-entrypoint.sh docker-entrypoint.sh 28 | 29 | ENTRYPOINT [ "sh", "docker-entrypoint.sh" ] 30 | -------------------------------------------------------------------------------- /server/prisma/migrations/20231020133514_anonymous_users/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "Member" ADD COLUMN "isAnonymous" BOOLEAN NOT NULL DEFAULT false, 3 | ALTER COLUMN "email" DROP NOT NULL; 4 | -------------------------------------------------------------------------------- /server/prisma/migrations/20231023224256_add_size_bytes_and_project_id_fields_to_attachment/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - Added the required column `projectId` to the `Attachment` table without a default value. This is not possible if the table is not empty. 5 | - Added the required column `sizeBytes` to the `Attachment` table without a default value. This is not possible if the table is not empty. 6 | 7 | */ 8 | -- AlterTable 9 | ALTER TABLE "Attachment" ADD COLUMN "projectId" TEXT NOT NULL, 10 | ADD COLUMN "sizeBytes" INTEGER NOT NULL; 11 | 12 | -- AddForeignKey 13 | ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE RESTRICT ON UPDATE CASCADE; 14 | -------------------------------------------------------------------------------- /server/prisma/migrations/20231026115736_add_type_and_metadata_fields_to_chat_message/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "ChatMessage" ADD COLUMN "metadata" JSONB NOT NULL DEFAULT '{}', 3 | ADD COLUMN "type" TEXT NOT NULL DEFAULT 'TEXT'; 4 | -------------------------------------------------------------------------------- /server/prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /server/scripts/docker-entrypoint.dev.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | npm install 6 | 7 | npx prisma generate 8 | npx prisma migrate deploy 9 | 10 | npm run start:dev 11 | -------------------------------------------------------------------------------- /server/scripts/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | npx prisma migrate deploy 6 | 7 | node dist/main.js $@ 8 | -------------------------------------------------------------------------------- /server/scripts/print-oas-docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | SKIP_ENV_VALIDATION=true DRY_RUN=true node dist/main.js $@ > /dev/null 6 | 7 | cat ./openapi.yaml 8 | -------------------------------------------------------------------------------- /server/src/agents/agents.constants.ts: -------------------------------------------------------------------------------- 1 | export const acceptedLogoMimeTypes = [ 2 | 'image/jpeg', 3 | 'image/jpg', 4 | 'image/png', 5 | 'image/webp', 6 | ]; 7 | -------------------------------------------------------------------------------- /server/src/agents/agents.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AgentsController } from './agents.controller'; 3 | import { AgentsService } from './agents.service'; 4 | 5 | describe('AgentsController', () => { 6 | let controller: AgentsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [AgentsController], 11 | providers: [AgentsService], 12 | }).compile(); 13 | 14 | controller = module.get(AgentsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /server/src/agents/agents.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ProjectBackendConnectionManagerModule } from 'src/project-backend-connection-manager/project-backend-connection-manager.module'; 3 | import { AttachmentsModule } from 'src/attachments/attachments.module'; 4 | import { ProjectsModule } from 'src/projects/projects.module'; 5 | import { TelemetryModule } from '../telemetry/telemetry.module'; 6 | import { AgentsController } from './agents.controller'; 7 | import { AgentsService } from './agents.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | ProjectsModule, 12 | AttachmentsModule, 13 | TelemetryModule, 14 | ProjectBackendConnectionManagerModule, 15 | ], 16 | controllers: [AgentsController], 17 | providers: [AgentsService], 18 | exports: [AgentsService], 19 | }) 20 | export class AgentsModule {} 21 | -------------------------------------------------------------------------------- /server/src/agents/agents.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AgentsService } from './agents.service'; 3 | 4 | describe('AgentsService', () => { 5 | let service: AgentsService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [AgentsService], 10 | }).compile(); 11 | 12 | service = module.get(AgentsService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/agents/dtos/agent-connection.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class AgentConnectionDto { 4 | @IsString() 5 | ip: string; 6 | 7 | @IsString() 8 | sid: string; 9 | 10 | @IsString() 11 | createdAt: string; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/agents/dtos/create.agent.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class CreateAgentDto { 4 | @IsString() 5 | name: string; 6 | 7 | @IsString() 8 | projectId: string; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/agents/dtos/created.agent.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class CreatedAgentDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | name: string; 9 | 10 | @IsString() 11 | projectId: string; 12 | 13 | @IsString() 14 | creatorId: string; 15 | 16 | @IsDate() 17 | createdAt: Date; 18 | 19 | @IsDate() 20 | updatedAt: Date; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/agents/dtos/deleted.agent.response.dto.ts: -------------------------------------------------------------------------------- 1 | export class DeletedAgentResponseDto { 2 | success: boolean; 3 | } 4 | -------------------------------------------------------------------------------- /server/src/agents/dtos/did-agent-ever-connect.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsBoolean } from 'class-validator'; 2 | 3 | export class DidAgentEverConnectResponse { 4 | @IsBoolean() 5 | didEverConnect: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/agents/dtos/get.agent.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class GetAgentResponseDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | name: string; 9 | 10 | @IsString() 11 | projectId: string; 12 | 13 | @IsString() 14 | creatorId: string; 15 | 16 | @IsDate() 17 | createdAt: Date; 18 | 19 | @IsDate() 20 | updatedAt: Date; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/agents/dtos/list-agent-connections.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { ValidateNested } from 'class-validator'; 3 | import { AgentConnectionDto } from './agent-connection.dto'; 4 | 5 | export class ListAgentConnectionsDto { 6 | @ValidateNested() 7 | @Type(() => AgentConnectionDto) 8 | items: AgentConnectionDto[]; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/agents/dtos/list.agents.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { 3 | IsArray, 4 | IsDate, 5 | IsNumber, 6 | IsString, 7 | ValidateNested, 8 | } from 'class-validator'; 9 | import { ListResponse } from '../../common/list.response'; 10 | 11 | class ListAgentItem { 12 | @IsString() 13 | id: string; 14 | 15 | @IsString() 16 | name: string; 17 | 18 | @IsString() 19 | projectId: string; 20 | 21 | @IsString() 22 | creatorId: string; 23 | 24 | @IsDate() 25 | createdAt: Date; 26 | 27 | @IsDate() 28 | updatedAt: Date; 29 | } 30 | 31 | export class ListAgentsResponseDto implements ListResponse { 32 | @IsArray() 33 | @ValidateNested({ each: true }) 34 | @Type(() => ListAgentItem) 35 | items: ListAgentItem[]; 36 | 37 | @IsNumber() 38 | total: number; 39 | } 40 | -------------------------------------------------------------------------------- /server/src/agents/dtos/update.agent.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class UpdateAgentDto { 4 | @IsString() 5 | name: string; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/agents/dtos/updated.agent.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class UpdatedAgentDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | name: string; 9 | 10 | @IsString() 11 | projectId: string; 12 | 13 | @IsString() 14 | creatorId: string; 15 | 16 | @IsDate() 17 | createdAt: Date; 18 | 19 | @IsDate() 20 | updatedAt: Date; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/app.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AppController } from './app.controller'; 3 | import { AppService } from './app.service'; 4 | 5 | describe('AppController', () => { 6 | let appController: AppController; 7 | 8 | beforeEach(async () => { 9 | const app: TestingModule = await Test.createTestingModule({ 10 | controllers: [AppController], 11 | providers: [AppService], 12 | }).compile(); 13 | 14 | appController = app.get(AppController); 15 | }); 16 | 17 | describe('root', () => { 18 | it('should return "Hello World!"', () => { 19 | expect(appController.getHello()).toBe('Hello World!'); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /server/src/app.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { AppService } from './app.service'; 3 | 4 | @Controller() 5 | export class AppController { 6 | constructor(private readonly appService: AppService) {} 7 | 8 | @Get() 9 | getHello(): string { 10 | return this.appService.getHello(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /server/src/app.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | @Injectable() 4 | export class AppService { 5 | getHello(): string { 6 | return 'Hello World!'; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /server/src/attachments/attachment-storage/attachment-storage.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | export interface AttachmentMetadata { 4 | attachmentId: string; 5 | filename: string; 6 | mimeType: string; 7 | checksumSha256: string; 8 | extension?: string; 9 | } 10 | 11 | // An attachment has to be retrievable by its sole ID, without any other 12 | // kind of metadata. The upload implementation should account for this. 13 | @Injectable() 14 | export abstract class AttachmentStorageService { 15 | abstract upload(data: Buffer, metadata: AttachmentMetadata): Promise; 16 | 17 | abstract download(attachmentId: string): Promise; 18 | 19 | abstract delete(attachmentId: string): Promise; 20 | } 21 | -------------------------------------------------------------------------------- /server/src/attachments/attachments.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AttachmentsController } from './attachments.controller'; 3 | 4 | describe('AttachmentsController', () => { 5 | let controller: AttachmentsController; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | controllers: [AttachmentsController], 10 | }).compile(); 11 | 12 | controller = module.get(AttachmentsController); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(controller).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/attachments/attachments.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AttachmentStorageService } from './attachment-storage/attachment-storage.service'; 3 | import { LocalAttachmentStorageService } from './attachment-storage/local-attachment-storage/local-attachment-storage.service'; 4 | import { AttachmentsService } from './attachments.service'; 5 | import { AttachmentsController } from './attachments.controller'; 6 | 7 | @Module({ 8 | imports: [], 9 | providers: [ 10 | AttachmentsService, 11 | { 12 | provide: AttachmentStorageService, 13 | useClass: LocalAttachmentStorageService, 14 | }, 15 | ], 16 | exports: [AttachmentsService, AttachmentStorageService], 17 | controllers: [AttachmentsController], 18 | }) 19 | export class AttachmentsModule {} 20 | -------------------------------------------------------------------------------- /server/src/attachments/attachments.types.ts: -------------------------------------------------------------------------------- 1 | export interface CreateAttachmentPayload { 2 | data: Buffer; 3 | mimeType: string; 4 | filename: string; 5 | size: number; 6 | projectId: string; 7 | isPublic?: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /server/src/auth-methods/auth-methods.config.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { registerAs } from '@nestjs/config'; 3 | import { validateEnv } from 'src/config/validate-env'; 4 | 5 | export interface AuthMethodsConfig { 6 | authMethodSecretEncryptionKey: string; 7 | authMethodSecretEncryptionAlgorithm: string; 8 | } 9 | 10 | export const authMethodsConfig = registerAs( 11 | 'AuthMethodsConfig', 12 | (): AuthMethodsConfig => { 13 | const env = validateEnv(process.env); 14 | 15 | return { 16 | authMethodSecretEncryptionKey: env.AES_ENCRYPTION_KEY, 17 | authMethodSecretEncryptionAlgorithm: 'aes-256-cbc', 18 | }; 19 | }, 20 | ); 21 | 22 | export const InjectAuthMethodsConfig = () => Inject(authMethodsConfig.KEY); 23 | -------------------------------------------------------------------------------- /server/src/auth-methods/auth-methods.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AuthMethodsController } from './auth-methods.controller'; 3 | import { AuthMethodsService } from './auth-methods.service'; 4 | 5 | describe('AuthMethodsController', () => { 6 | let controller: AuthMethodsController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [AuthMethodsController], 11 | providers: [AuthMethodsService], 12 | }).compile(); 13 | 14 | controller = module.get(AuthMethodsController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /server/src/auth-methods/auth-methods.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TelemetryModule } from '../telemetry/telemetry.module'; 3 | import { AuthMethodsController } from './auth-methods.controller'; 4 | import { AuthMethodsService } from './auth-methods.service'; 5 | 6 | @Module({ 7 | controllers: [AuthMethodsController], 8 | providers: [AuthMethodsService], 9 | exports: [AuthMethodsService], 10 | imports: [TelemetryModule], 11 | }) 12 | export class AuthMethodsModule {} 13 | -------------------------------------------------------------------------------- /server/src/auth-methods/auth-methods.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { AuthMethodsService } from './auth-methods.service'; 3 | 4 | describe('AuthMethodsService', () => { 5 | let service: AuthMethodsService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [AuthMethodsService], 10 | }).compile(); 11 | 12 | service = module.get(AuthMethodsService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/create.auth-method.dto.ts: -------------------------------------------------------------------------------- 1 | import { AuthProvider } from '@prisma/client'; 2 | import { Type } from 'class-transformer'; 3 | import { 4 | IsArray, 5 | IsBoolean, 6 | IsIn, 7 | IsOptional, 8 | IsString, 9 | ValidateNested, 10 | } from 'class-validator'; 11 | 12 | const AuthProviders = Object.values(AuthProvider); 13 | 14 | export class CreateAuthMethodDto { 15 | @IsIn(AuthProviders) 16 | provider: AuthProvider; 17 | 18 | @IsString() 19 | projectId: string; 20 | 21 | @IsBoolean() 22 | isEnabled: boolean; 23 | 24 | @IsOptional() 25 | @IsString() 26 | clientId: string; 27 | 28 | @IsOptional() 29 | @IsString() 30 | clientSecret: string; 31 | 32 | @IsArray() 33 | @ValidateNested({ each: true }) 34 | @Type(() => String) 35 | @IsOptional() 36 | scopes: string[]; 37 | } 38 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/created.auth-method.dto.ts: -------------------------------------------------------------------------------- 1 | import { AuthMethodItemDto } from './auth-method.item.dto'; 2 | 3 | export class CreatedAuthMethodDto extends AuthMethodItemDto {} 4 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/created.demo.auth-method.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsBoolean } from 'class-validator'; 2 | 3 | export class CreatedDemoAuthMethodsDto { 4 | @IsBoolean() 5 | success: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/list.auth-method.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { IsArray, IsNumber, ValidateNested } from 'class-validator'; 3 | import { ListResponse } from '../../common/list.response'; 4 | import { AuthMethodItemDto } from './auth-method.item.dto'; 5 | 6 | class ListAuthMethodItem extends AuthMethodItemDto {} 7 | 8 | export class ListAuthMethodResponseDto 9 | implements ListResponse 10 | { 11 | @IsArray() 12 | @ValidateNested({ each: true }) 13 | @Type(() => ListAuthMethodItem) 14 | items: ListAuthMethodItem[]; 15 | 16 | @IsNumber() 17 | total: number; 18 | } 19 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/upsert.auth-method.dto.ts: -------------------------------------------------------------------------------- 1 | import { AuthMethodType, AuthProvider } from '@prisma/client'; 2 | import { Type } from 'class-transformer'; 3 | import { 4 | IsArray, 5 | IsBoolean, 6 | IsIn, 7 | IsOptional, 8 | IsString, 9 | ValidateNested, 10 | } from 'class-validator'; 11 | 12 | const AuthMethodTypes = Object.values(AuthMethodType); 13 | const AuthProviders = Object.values(AuthProvider); 14 | 15 | export class UpsertAuthMethodDto { 16 | @IsIn(AuthProviders) 17 | provider: AuthProvider; 18 | 19 | @IsString() 20 | projectId: string; 21 | 22 | @IsBoolean() 23 | isEnabled: boolean; 24 | 25 | @IsString() 26 | clientId: string; 27 | 28 | @IsString() 29 | clientSecret: string; 30 | 31 | @IsArray() 32 | @ValidateNested({ each: true }) 33 | @Type(() => String) 34 | @IsOptional() 35 | scopes: string[]; 36 | } 37 | -------------------------------------------------------------------------------- /server/src/auth-methods/dtos/upserted.auth-method.dto.ts: -------------------------------------------------------------------------------- 1 | import { AuthMethodItemDto } from './auth-method.item.dto'; 2 | 3 | export class UpsertedAuthMethodDto extends AuthMethodItemDto {} 4 | -------------------------------------------------------------------------------- /server/src/chat-messages/chat-messages.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AttachmentsModule } from 'src/attachments/attachments.module'; 3 | import { ConversationsModule } from 'src/conversations/conversations.module'; 4 | import { ChatMessagesController } from './chat-messages.controller'; 5 | import { ChatMessagesService } from './chat-messages.service'; 6 | 7 | @Module({ 8 | imports: [ConversationsModule, AttachmentsModule], 9 | providers: [ChatMessagesService], 10 | exports: [ChatMessagesService], 11 | controllers: [ChatMessagesController], 12 | }) 13 | export class ChatMessagesModule {} 14 | -------------------------------------------------------------------------------- /server/src/chat-messages/chat-messages.types.ts: -------------------------------------------------------------------------------- 1 | import { ChatMessageSource, MessageFormat } from 'prisma/prisma-client'; 2 | 3 | export interface BaseChatMessagePayload { 4 | text: string; 5 | conversationId: string; 6 | format: MessageFormat; 7 | metadata?: any; 8 | type: MessageType; 9 | source: ChatMessageSource; 10 | agentId?: string; 11 | } 12 | 13 | export type CreateUserChatMessagePayload = BaseChatMessagePayload; 14 | 15 | export type CreateSystemChatMessagePayload = BaseChatMessagePayload; 16 | 17 | export const MessageTypes = ['TEXT', 'ECHART'] as const; 18 | 19 | export type MessageType = (typeof MessageTypes)[number]; 20 | 21 | export interface EchartMetadata { 22 | chartType: string; 23 | } 24 | -------------------------------------------------------------------------------- /server/src/common/list.response.ts: -------------------------------------------------------------------------------- 1 | export interface ListResponse { 2 | items: T[]; 3 | total: number; 4 | } 5 | -------------------------------------------------------------------------------- /server/src/common/mime.ts: -------------------------------------------------------------------------------- 1 | export const mimeTypeToExtension: Record = { 2 | 'image/jpeg': 'jpg', 3 | 'image/png': 'png', 4 | 'image/jpg': 'jpg', 5 | 'image/webp': 'webp', 6 | 'application/pdf': 'pdf', 7 | 'application/json': 'json', 8 | }; 9 | -------------------------------------------------------------------------------- /server/src/common/ms-time.ts: -------------------------------------------------------------------------------- 1 | export const seconds = (n: number) => n * 1000; 2 | export const minutes = (n: number) => seconds(n) * 60; 3 | export const hours = (n: number) => minutes(n) * 60; 4 | export const days = (n: number) => hours(n) * 24; 5 | export const weeks = (n: number) => days(n) * 7; 6 | export const months = (n: number) => days(n) * 30; 7 | export const years = (n: number) => days(n) * 365; 8 | -------------------------------------------------------------------------------- /server/src/common/paginated.query.dto.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from 'class-transformer'; 2 | import { IsNumber, Max, Min } from 'class-validator'; 3 | 4 | export class PaginatedQueryDto { 5 | @IsNumber() 6 | @Min(1) 7 | @Transform(({ value }) => Number.parseInt(value, 10)) 8 | page: number; 9 | 10 | @IsNumber() 11 | @Min(1) 12 | @Max(1000) 13 | @Transform(({ value }) => Number.parseInt(value, 10)) 14 | limit: number; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/common/paginated.response.ts: -------------------------------------------------------------------------------- 1 | export interface PaginatedResponse { 2 | items: T[]; 3 | resultCount: number; 4 | totalCount: number; 5 | hasMore: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/common/result.ts: -------------------------------------------------------------------------------- 1 | export type Result = { ok: true; value: T } | { ok: false; error: E }; 2 | export type PResult = Promise>; 3 | 4 | export const ok = (value: T): Result => ({ ok: true, value }); 5 | export const err = (error: E): Result => ({ ok: false, error }); 6 | -------------------------------------------------------------------------------- /server/src/conversations/conversations.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConversationsController } from './conversations.controller'; 3 | import { ConversationsService } from './conversations.service'; 4 | 5 | @Module({ 6 | providers: [ConversationsService], 7 | controllers: [ConversationsController], 8 | exports: [ConversationsService], 9 | }) 10 | export class ConversationsModule {} 11 | -------------------------------------------------------------------------------- /server/src/conversations/conversations.types.ts: -------------------------------------------------------------------------------- 1 | export interface CreateConversationPayload { 2 | id: string; 3 | projectId: string; 4 | memberId: string; 5 | } 6 | 7 | export interface FindAllConversationsPayload { 8 | projectId: string; 9 | memberId: string; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/conversations/dto/get-all-conversations.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class GetAllConversationsDto { 4 | @IsString() 5 | readonly projectId: string; 6 | } -------------------------------------------------------------------------------- /server/src/frontend-connection-manager/frontend-connection-manager.constants.ts: -------------------------------------------------------------------------------- 1 | export const frontend_namespace = 'frontend'; 2 | -------------------------------------------------------------------------------- /server/src/frontend-connection-manager/frontend-connection-manager.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { FrontendConnectionManagerService } from './frontend-connection-manager.service'; 3 | 4 | @Module({ 5 | imports: [], 6 | providers: [FrontendConnectionManagerService], 7 | exports: [FrontendConnectionManagerService], 8 | }) 9 | export class FrontendConnectionManagerModule {} 10 | -------------------------------------------------------------------------------- /server/src/frontend-connection-manager/frontend-connection-manager.types.ts: -------------------------------------------------------------------------------- 1 | import { Socket } from 'socket.io'; 2 | 3 | export interface FrontendConnection { 4 | socket: Socket; 5 | projectId: string; 6 | createdAt: Date; 7 | key: string; 8 | memberId: string; 9 | host: string; 10 | } 11 | 12 | export interface RegisterFrontendConnectionPayload { 13 | projectId: string; 14 | socket: Socket; 15 | memberId: string; 16 | host: string; 17 | } 18 | 19 | export interface ComputeFrontendConnectionKeyPayload { 20 | projectId: string; 21 | memberId: string; 22 | } 23 | -------------------------------------------------------------------------------- /server/src/frontend-connection/dto/frontend-chat-message.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { IsOptional, IsString, ValidateNested } from 'class-validator'; 3 | import { BaseRealtimeMessageDto } from 'src/common/base-realtime-message.dto'; 4 | 5 | class AttachmentDto { 6 | @IsString() 7 | id: string; 8 | } 9 | 10 | class FrontendChatMessageDtoData { 11 | @IsString() 12 | text: string; 13 | 14 | @IsOptional() 15 | @IsString() 16 | conversationId: string; 17 | 18 | @ValidateNested({ each: true }) 19 | @Type(() => AttachmentDto) 20 | attachments: AttachmentDto[]; 21 | } 22 | 23 | export class FrontendChatMessageDto extends BaseRealtimeMessageDto { 24 | @ValidateNested() 25 | @Type(() => FrontendChatMessageDtoData) 26 | data: FrontendChatMessageDtoData; 27 | } 28 | -------------------------------------------------------------------------------- /server/src/iam/iam.decorators.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | import { AuthMethod } from './iam.types'; 3 | 4 | export const REQUIRE_AUTH_METHOD_METADATA_KEY = 'require-auth'; 5 | 6 | export const RequireAuthMethod = (...method: AuthMethod[]) => 7 | SetMetadata(REQUIRE_AUTH_METHOD_METADATA_KEY, method); 8 | -------------------------------------------------------------------------------- /server/src/iam/server-sdk-auth/server-sdk-auth.types.ts: -------------------------------------------------------------------------------- 1 | export interface SdkUser { 2 | projectId: string; 3 | } 4 | -------------------------------------------------------------------------------- /server/src/mailer/mailer.config.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { registerAs } from '@nestjs/config'; 3 | import { validateEnv } from 'src/config/validate-env'; 4 | 5 | export interface MailerConfig { 6 | host: string; 7 | port: number; 8 | user: string; 9 | password: string; 10 | senderAddress: string; 11 | senderName: string; 12 | } 13 | 14 | export const mailerConfig = registerAs( 15 | 'MailerConfig', 16 | (): MailerConfig => { 17 | const env = validateEnv(process.env); 18 | 19 | return { 20 | host: env.SMTP_HOST, 21 | port: env.SMTP_PORT, 22 | user: env.SMTP_USERNAME, 23 | password: env.SMTP_PASSWORD, 24 | senderAddress: env.EMAIL_SENDER_ADDRESS, 25 | senderName: env.EMAIL_SENDER_NAME, 26 | }; 27 | }, 28 | ); 29 | 30 | export const InjectMailerConfig = () => Inject(mailerConfig.KEY); 31 | -------------------------------------------------------------------------------- /server/src/mailer/mailer.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MailerService } from './mailer.service'; 3 | 4 | @Module({ 5 | providers: [MailerService], 6 | exports: [MailerService], 7 | }) 8 | export class MailerModule {} 9 | -------------------------------------------------------------------------------- /server/src/mailer/mailer.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { MailerService } from './mailer.service'; 3 | 4 | describe('MailerService', () => { 5 | let service: MailerService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [MailerService], 10 | }).compile(); 11 | 12 | service = module.get(MailerService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/members/dtos/list.members.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | import { PaginatedResponse } from '../../common/paginated.response'; 3 | 4 | export class MemberItem { 5 | @IsString() 6 | id: string; 7 | 8 | @IsString() 9 | email: string | null; 10 | 11 | @IsString() 12 | firstName: string | null; 13 | 14 | @IsString() 15 | lastName: string | null; 16 | 17 | @IsDate() 18 | createdAt: Date; 19 | 20 | @IsDate() 21 | updatedAt: Date; 22 | 23 | @IsDate() 24 | verifiedAt: Date | null; 25 | } 26 | 27 | export class ListMembersResponseDto implements PaginatedResponse { 28 | items: MemberItem[]; 29 | resultCount: number; 30 | totalCount: number; 31 | hasMore: boolean; 32 | } 33 | -------------------------------------------------------------------------------- /server/src/members/dtos/login.member.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | import { SanitizedMemberDto } from './sanitized.member.dto'; 3 | 4 | export class LoginMemberResponseDto { 5 | @IsString() 6 | accessToken: string; 7 | 8 | member: SanitizedMemberDto; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/members/dtos/member.whoami.result.dto.ts: -------------------------------------------------------------------------------- 1 | import { SanitizedMemberDto } from './sanitized.member.dto'; 2 | 3 | export class MemberWhoAmIResultDto extends SanitizedMemberDto {} 4 | -------------------------------------------------------------------------------- /server/src/members/dtos/oauth.authorize.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class oauthAuthorizeDto { 4 | @IsString() 5 | code: string; 6 | 7 | @IsString() 8 | state: string; 9 | 10 | @IsString() 11 | redirectUri: string; 12 | 13 | @IsString() 14 | projectId: string; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/members/dtos/register.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class RegisterResponseDto { 4 | @IsString() 5 | email: string | null; 6 | 7 | @IsDate() 8 | createdAt: Date; 9 | 10 | @IsDate() 11 | updatedAt: Date; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/members/dtos/request.passwordless-email.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class RequestPasswordlessEmailDto { 4 | @IsString() 5 | email: string; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/members/dtos/sanitized.member.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class SanitizedMemberDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | email: string | null; 9 | 10 | @IsString() 11 | fullName: string | null; 12 | 13 | @IsString() 14 | firstName: string | null; 15 | 16 | @IsString() 17 | lastName: string | null; 18 | 19 | @IsString() 20 | profilePictureUrl: string | null; 21 | 22 | @IsDate() 23 | verifiedAt: Date | null; 24 | 25 | @IsDate() 26 | createdAt: Date; 27 | 28 | @IsDate() 29 | updatedAt: Date; 30 | } 31 | -------------------------------------------------------------------------------- /server/src/members/dtos/verify-passwordless-email.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsString } from 'class-validator'; 2 | 3 | export class VerifyPasswordlessEmailDto { 4 | @IsEmail() 5 | email: string; 6 | 7 | @IsString() 8 | code: string; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/members/members.config.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { registerAs } from '@nestjs/config'; 3 | import { validateEnv } from 'src/config/validate-env'; 4 | 5 | export interface MembersConfig { 6 | accessTokenSecret: string; 7 | accessTokenExpirationTime: string; 8 | authCodeExpirationDelayInMinutes: number; 9 | } 10 | 11 | export const membersConfig = registerAs( 12 | 'MembersConfig', 13 | (): MembersConfig => { 14 | const env = validateEnv(process.env); 15 | 16 | return { 17 | accessTokenSecret: env.MEMBERS_ACCESS_TOKEN_SECRET, 18 | accessTokenExpirationTime: '24h', 19 | authCodeExpirationDelayInMinutes: 20 | env.MEMBERS_AUTH_CODE_EXPIRATION_DELAY_IN_MINUTES, 21 | }; 22 | }, 23 | ); 24 | 25 | export const InjectMembersConfig = () => Inject(membersConfig.KEY); 26 | -------------------------------------------------------------------------------- /server/src/members/members.controller.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { MembersController } from './members.controller'; 3 | import { MembersService } from './members.service'; 4 | 5 | describe('MembersController', () => { 6 | let controller: MembersController; 7 | 8 | beforeEach(async () => { 9 | const module: TestingModule = await Test.createTestingModule({ 10 | controllers: [MembersController], 11 | providers: [MembersService], 12 | }).compile(); 13 | 14 | controller = module.get(MembersController); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(controller).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /server/src/members/members.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AuthMethodsModule } from '../auth-methods/auth-methods.module'; 3 | import { MailerModule } from '../mailer/mailer.module'; 4 | import { OauthProvidersModule } from '../oauth-providers/oauth-providers.module'; 5 | import { MembersController } from './members.controller'; 6 | import { MembersService } from './members.service'; 7 | 8 | @Module({ 9 | imports: [MailerModule, OauthProvidersModule, AuthMethodsModule], 10 | controllers: [MembersController], 11 | providers: [MembersService], 12 | exports: [MembersService], 13 | }) 14 | export class MembersModule {} 15 | -------------------------------------------------------------------------------- /server/src/members/members.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { MembersService } from './members.service'; 3 | 4 | describe('MembersService', () => { 5 | let service: MembersService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [MembersService], 10 | }).compile(); 11 | 12 | service = module.get(MembersService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/members/members.types.ts: -------------------------------------------------------------------------------- 1 | import { JWTPayload } from 'jose'; 2 | 3 | export type AccessTokenPayload = { 4 | sub: string; 5 | email: string | null; 6 | firstName: string | null; 7 | lastName: string | null; 8 | projectId: string; 9 | }; 10 | 11 | export const isAccessTokenPayload = ( 12 | payload: JWTPayload, 13 | ): payload is AccessTokenPayload => { 14 | return typeof payload.sub === 'string'; 15 | }; 16 | -------------------------------------------------------------------------------- /server/src/oauth-providers/google/google.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { GoogleService } from './google.service'; 3 | 4 | describe('GoogleService', () => { 5 | let service: GoogleService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [GoogleService], 10 | }).compile(); 11 | 12 | service = module.get(GoogleService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/oauth-providers/oauth-providers.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { GoogleService } from './google/google.service'; 3 | 4 | @Module({ 5 | providers: [GoogleService], 6 | exports: [GoogleService], 7 | }) 8 | export class OauthProvidersModule {} 9 | -------------------------------------------------------------------------------- /server/src/openapi-tools/index.ts: -------------------------------------------------------------------------------- 1 | export * from './openapi-tools.module'; 2 | export * from './openapi.service'; 3 | export * from './openapi-nest.factory'; 4 | export * from './openapi-file-generator/openapi-file-generator.service'; 5 | -------------------------------------------------------------------------------- /server/src/openapi-tools/openapi-file-generator/openapi-file-generator.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { OpenApiFileGeneratorService } from './openapi-file-generator.service'; 3 | 4 | describe('OpenApiFileGeneratorService', () => { 5 | let service: OpenApiFileGeneratorService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [OpenApiFileGeneratorService], 10 | }).compile(); 11 | 12 | service = module.get( 13 | OpenApiFileGeneratorService, 14 | ); 15 | }); 16 | 17 | it('should be defined', () => { 18 | expect(service).toBeDefined(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /server/src/openapi-tools/openapi-tools.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { OpenApiFileGeneratorService } from './openapi-file-generator/openapi-file-generator.service'; 3 | import { OpenApiService } from './openapi.service'; 4 | 5 | @Module({ 6 | providers: [OpenApiService, OpenApiFileGeneratorService], 7 | exports: [OpenApiService], 8 | }) 9 | export class OpenApiToolsModule {} 10 | -------------------------------------------------------------------------------- /server/src/prisma/prisma.module.ts: -------------------------------------------------------------------------------- 1 | import { Global, Module } from '@nestjs/common'; 2 | import { PrismaService } from './prisma.service'; 3 | 4 | @Global() 5 | @Module({ 6 | providers: [PrismaService], 7 | exports: [PrismaService], 8 | }) 9 | export class PrismaModule {} 10 | -------------------------------------------------------------------------------- /server/src/prisma/prisma.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, OnModuleInit } from '@nestjs/common'; 2 | import { PrismaClient } from '@prisma/client'; 3 | 4 | @Injectable() 5 | export class PrismaService extends PrismaClient implements OnModuleInit { 6 | async onModuleInit() { 7 | await this.$connect(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/dto/register-agent-connection.dto.ts: -------------------------------------------------------------------------------- 1 | export class RegisterAgentConnectionDto { 2 | projectId: string; 3 | agentId: string; 4 | } 5 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/dto/serialized-project-backend-connection.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class SerializedProjectBackendConnectionDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | createdAt: string; 9 | 10 | @IsString() 11 | projectId: string; 12 | 13 | @IsString() 14 | ipAddress: string; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/project-backend-connection-manager.constants.ts: -------------------------------------------------------------------------------- 1 | export const AGENT_SOCKETIO_NAMESPACE = 'agent'; 2 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/project-backend-connection-manager.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@nestjs/common'; 2 | 3 | @Controller('agent-connection-manager') 4 | export class ProjectBackendConnectionManagerController { 5 | constructor() {} 6 | } 7 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/project-backend-connection-manager.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { FrontendConnectionManagerModule } from 'src/frontend-connection-manager/frontend-connection-manager.module'; 3 | import { ProjectBackendConnectionManagerController } from './project-backend-connection-manager.controller'; 4 | import { ProjectBackendConnectionManagerService } from './project-backend-connection-manager.service'; 5 | 6 | @Module({ 7 | imports: [FrontendConnectionManagerModule], 8 | providers: [ProjectBackendConnectionManagerService], 9 | exports: [ProjectBackendConnectionManagerService], 10 | controllers: [ProjectBackendConnectionManagerController], 11 | }) 12 | export class ProjectBackendConnectionManagerModule {} 13 | -------------------------------------------------------------------------------- /server/src/project-backend-connection-manager/project-backend-connection-manager.types.ts: -------------------------------------------------------------------------------- 1 | import { Socket } from 'socket.io'; 2 | 3 | export interface AgentConnection { 4 | socket: Socket; 5 | projectId: string; 6 | key: string; 7 | createdAt: Date; 8 | ip: string; 9 | } 10 | 11 | export interface RegisterAgentConnectionPayload { 12 | socket: Socket; 13 | projectId: string; 14 | ip: string; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/project-backend-connection/dto/stream-chat-message-token.dto.ts: -------------------------------------------------------------------------------- 1 | import { MessageFormat } from '@prisma/client'; 2 | import { Type } from 'class-transformer'; 3 | import { IsEnum, IsString, ValidateNested } from 'class-validator'; 4 | import { BaseRealtimeMessageDto } from 'src/common/base-realtime-message.dto'; 5 | 6 | class StreamChatMessageTokenDtoData { 7 | @IsString() 8 | text: string; 9 | 10 | @IsString() 11 | conversationId: string; 12 | 13 | @IsString() 14 | messageId: string; 15 | 16 | @IsEnum(MessageFormat) 17 | format: MessageFormat; 18 | 19 | @IsString() 20 | agentId: string; 21 | } 22 | 23 | export class StreamChatMessageTokenDto extends BaseRealtimeMessageDto { 24 | @ValidateNested() 25 | @Type(() => StreamChatMessageTokenDtoData) 26 | data: StreamChatMessageTokenDtoData; 27 | } 28 | -------------------------------------------------------------------------------- /server/src/projects/dtos/create.project.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class CreateProjectDto { 4 | @IsString() 5 | name: string; 6 | 7 | @IsString() 8 | slug: string; 9 | 10 | @IsString() 11 | organizationId: string; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/projects/dtos/created.project.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class CreatedProjectDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | name: string; 9 | 10 | @IsString() 11 | slug: string; 12 | 13 | @IsString() 14 | organizationId: string; 15 | 16 | @IsString() 17 | creatorId: string; 18 | 19 | @IsDate() 20 | createdAt: Date; 21 | 22 | @IsDate() 23 | updatedAt: Date; 24 | } 25 | -------------------------------------------------------------------------------- /server/src/projects/dtos/get-realtime-connections.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { ValidateNested } from 'class-validator'; 3 | import { SerializedProjectBackendConnectionDto } from '../../project-backend-connection-manager/dto/serialized-project-backend-connection.dto'; 4 | 5 | export class GetRealtimeConnectionsResponseDto { 6 | @ValidateNested({ each: true }) 7 | @Type(() => SerializedProjectBackendConnectionDto) 8 | items: SerializedProjectBackendConnectionDto[]; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/projects/dtos/get.public.config.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class GetPublicConfigDto { 4 | @IsString() 5 | hostname: string; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/projects/dtos/list.projects.result.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from 'class-transformer'; 2 | import { 3 | IsArray, 4 | IsDate, 5 | IsNumber, 6 | IsString, 7 | ValidateNested, 8 | } from 'class-validator'; 9 | import { ListResponse } from '../../common/list.response'; 10 | 11 | export class ListProjectItemDto { 12 | @IsString() 13 | id: string; 14 | 15 | @IsString() 16 | name: string; 17 | 18 | @IsString() 19 | slug: string; 20 | 21 | @IsString() 22 | organizationId: string; 23 | 24 | @IsString() 25 | creatorId: string; 26 | 27 | @IsDate() 28 | createdAt: Date; 29 | 30 | @IsDate() 31 | updatedAt: Date; 32 | } 33 | 34 | export class ListProjectsResultDto implements ListResponse { 35 | @IsArray() 36 | @ValidateNested({ each: true }) 37 | @Type(() => ListProjectItemDto) 38 | items: ListProjectItemDto[]; 39 | 40 | @IsNumber() 41 | total: number; 42 | } 43 | -------------------------------------------------------------------------------- /server/src/projects/dtos/project.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class ProjectDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | name: string; 9 | 10 | @IsString() 11 | slug: string; 12 | 13 | @IsString() 14 | organizationId: string; 15 | 16 | @IsString() 17 | creatorId: string; 18 | 19 | @IsDate() 20 | createdAt: Date; 21 | 22 | @IsDate() 23 | updatedAt: Date; 24 | } 25 | -------------------------------------------------------------------------------- /server/src/projects/dtos/project.exists.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsBoolean } from 'class-validator'; 2 | 3 | export class ProjectExistsResponseDto { 4 | @IsBoolean() 5 | exists: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/projects/projects.config.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { registerAs } from '@nestjs/config'; 3 | import { validateEnv } from 'src/config/validate-env'; 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-empty-interface 6 | export interface ProjectsConfig {} 7 | 8 | export const projectsConfig = registerAs( 9 | 'ProjectsConfig', 10 | (): ProjectsConfig => { 11 | const env = validateEnv(process.env); 12 | 13 | console.log('env', env); 14 | 15 | return {}; 16 | }, 17 | ); 18 | 19 | export const InjectProjectsConfig = () => Inject(projectsConfig.KEY); 20 | -------------------------------------------------------------------------------- /server/src/projects/projects.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ProjectBackendConnectionManagerModule } from 'src/project-backend-connection-manager/project-backend-connection-manager.module'; 3 | import { TelemetryModule } from '../telemetry/telemetry.module'; 4 | import { ProjectsController } from './projects.controller'; 5 | import { ProjectsService } from './projects.service'; 6 | 7 | @Module({ 8 | controllers: [ProjectsController], 9 | providers: [ProjectsService], 10 | exports: [ProjectsService], 11 | imports: [TelemetryModule, ProjectBackendConnectionManagerModule], 12 | }) 13 | export class ProjectsModule {} 14 | -------------------------------------------------------------------------------- /server/src/projects/projects.types.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/server/src/projects/projects.types.ts -------------------------------------------------------------------------------- /server/src/sdk-secrets/dtos/create.sdk-secret.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsOptional, IsString } from 'class-validator'; 2 | 3 | export class CreateSdkSecretDto { 4 | @IsString() 5 | @IsOptional() 6 | description?: string; 7 | 8 | @IsString() 9 | projectId: string; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/dtos/created.sdk-secret.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | import { SanitizedSdkSecretDto } from './sanitized.sdk-secret.dto'; 3 | 4 | export class CreatedSdkSecretDto extends SanitizedSdkSecretDto { 5 | @IsString() 6 | clearValue: string; 7 | } 8 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/dtos/list.sdk-secret.dto.ts: -------------------------------------------------------------------------------- 1 | import { PaginatedResponse } from '../../common/paginated.response'; 2 | import { SanitizedSdkSecretDto } from './sanitized.sdk-secret.dto'; 3 | export class ListSdkSecretDto 4 | implements PaginatedResponse 5 | { 6 | items: SanitizedSdkSecretDto[]; 7 | resultCount: number; 8 | hasMore: boolean; 9 | totalCount: number; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/dtos/revoke.sdk-secret.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsBoolean } from 'class-validator'; 2 | 3 | export class RevokeSdkSecretDto { 4 | @IsBoolean() 5 | isRevoked: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/dtos/sanitized.sdk-secret.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsString } from 'class-validator'; 2 | 3 | export class SanitizedSdkSecretDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsString() 8 | description: string | null; 9 | 10 | @IsString() 11 | projectId: string; 12 | 13 | @IsString() 14 | preview: string; 15 | 16 | @IsDate() 17 | createdAt: Date; 18 | 19 | @IsDate() 20 | updatedAt: Date; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/sdk-secrets.errors.ts: -------------------------------------------------------------------------------- 1 | export const VerifyIfIsProjectUserErrors = [ 2 | 'ProjectNotFound', 3 | 'NotAProjectUser', 4 | ] as const; 5 | 6 | export type VerifyIfIsProjectUserError = 7 | (typeof VerifyIfIsProjectUserErrors)[number]; 8 | -------------------------------------------------------------------------------- /server/src/sdk-secrets/sdk-secrets.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TelemetryModule } from '../telemetry/telemetry.module'; 3 | import { SdkSecretsController } from './sdk-secrets.controller'; 4 | import { SdkSecretsService } from './sdk-secrets.service'; 5 | 6 | @Module({ 7 | imports: [TelemetryModule], 8 | controllers: [SdkSecretsController], 9 | providers: [SdkSecretsService], 10 | exports: [SdkSecretsService], 11 | }) 12 | export class SdkSecretsModule {} 13 | -------------------------------------------------------------------------------- /server/src/telemetry/telemetry.config.ts: -------------------------------------------------------------------------------- 1 | import { Inject } from '@nestjs/common'; 2 | import { registerAs } from '@nestjs/config'; 3 | import { validateEnv } from 'src/config/validate-env'; 4 | 5 | export interface TelemetryConfig { 6 | telemetryKey?: string; 7 | } 8 | 9 | export const telemetryConfig = registerAs( 10 | 'TelemetryConfig', 11 | (): TelemetryConfig => { 12 | const env = validateEnv(process.env); 13 | 14 | return { 15 | telemetryKey: env.SECRET_TELEMETRY_KEY, 16 | }; 17 | }, 18 | ); 19 | 20 | export const InjectTelemetryConfig = () => Inject(telemetryConfig.KEY); 21 | -------------------------------------------------------------------------------- /server/src/telemetry/telemetry.module.ts: -------------------------------------------------------------------------------- 1 | import { Global, Module } from '@nestjs/common'; 2 | import { TelemetryService } from './telemetry.service'; 3 | 4 | @Global() 5 | @Module({ 6 | providers: [TelemetryService], 7 | exports: [TelemetryService], 8 | }) 9 | export class TelemetryModule {} 10 | -------------------------------------------------------------------------------- /server/src/telemetry/telemetry.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { TelemetryService } from './telemetry.service'; 3 | 4 | describe('TelemetryService', () => { 5 | let service: TelemetryService; 6 | 7 | beforeEach(async () => { 8 | const module: TestingModule = await Test.createTestingModule({ 9 | providers: [TelemetryService], 10 | }).compile(); 11 | 12 | service = module.get(TelemetryService); 13 | }); 14 | 15 | it('should be defined', () => { 16 | expect(service).toBeDefined(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /server/src/telemetry/telemetry.types.ts: -------------------------------------------------------------------------------- 1 | export const TelemetryEvents = [ 2 | 'User Logged In', 3 | 'User Created', 4 | 'Project Created', 5 | 'AuthMethod Configured', 6 | 'Demo AuthMethod Configured', 7 | 'Agent Created', 8 | 'Agent Updated', 9 | 'Agent Deleted', 10 | 'SDK Secret Created', 11 | 'Project Backend Connected', 12 | 'Message Sent', 13 | ] as const; 14 | export type TelemetryEvent = (typeof TelemetryEvents)[number]; 15 | -------------------------------------------------------------------------------- /server/src/users/dtos/login.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { SanitizedUserResponseDto } from './sanitized.user.response.dto'; 2 | 3 | export class LoginResponseDto { 4 | accessToken: string; 5 | user: SanitizedUserResponseDto; 6 | } 7 | -------------------------------------------------------------------------------- /server/src/users/dtos/login.user.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsString, MinLength } from 'class-validator'; 2 | 3 | export class LoginUserDto { 4 | @IsEmail() 5 | email: string; 6 | 7 | @IsString() 8 | @MinLength(6) 9 | password: string; 10 | } 11 | -------------------------------------------------------------------------------- /server/src/users/dtos/login.user.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | import { SanitizedUserResponseDto } from './sanitized.user.response.dto'; 3 | 4 | export class LoginUserResponseDto { 5 | @IsString() 6 | accessToken: string; 7 | 8 | user: SanitizedUserResponseDto; 9 | } 10 | -------------------------------------------------------------------------------- /server/src/users/dtos/oauth.authorize.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsString } from 'class-validator'; 2 | 3 | export class oauthUserAuthorizeDto { 4 | @IsString() 5 | code: string; 6 | 7 | @IsString() 8 | state: string; 9 | 10 | @IsString() 11 | redirectUri: string; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/users/dtos/oauthlogin.user.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { LoginResponseDto } from './login.response.dto'; 2 | 3 | export class OAuthLoginUserResponseDto extends LoginResponseDto { 4 | created: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /server/src/users/dtos/register.user.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsEmail, IsString, MinLength } from 'class-validator'; 2 | 3 | export class RegisterUserDto { 4 | @IsEmail() 5 | email: string; 6 | 7 | @IsString() 8 | @MinLength(6) 9 | password: string; 10 | 11 | @IsString() 12 | @MinLength(2) 13 | fullName: string; 14 | } 15 | -------------------------------------------------------------------------------- /server/src/users/dtos/sanitized.user.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { IsDate, IsEmail, IsString } from 'class-validator'; 2 | 3 | export class SanitizedUserResponseDto { 4 | @IsString() 5 | id: string; 6 | 7 | @IsEmail() 8 | email: string; 9 | 10 | @IsString() 11 | fullName: string; 12 | 13 | @IsString() 14 | profilePictureUrl: string | null; 15 | 16 | @IsDate() 17 | verifiedAt: Date | null; 18 | } 19 | -------------------------------------------------------------------------------- /server/src/users/dtos/user.created.response.dto.ts: -------------------------------------------------------------------------------- 1 | import { SanitizedUserResponseDto } from './sanitized.user.response.dto'; 2 | 3 | export class UserCreatedResponseDto extends SanitizedUserResponseDto {} 4 | -------------------------------------------------------------------------------- /server/src/users/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentlabs-dev/agentlabs/39eb66fe15d039ffb9ba4e7a4415b97e8ed7c53a/server/src/users/templates/.gitkeep -------------------------------------------------------------------------------- /server/src/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MailerModule } from '../mailer/mailer.module'; 3 | import { OauthProvidersModule } from '../oauth-providers/oauth-providers.module'; 4 | import { TelemetryModule } from '../telemetry/telemetry.module'; 5 | import { UsersController } from './users.controller'; 6 | import { UsersService } from './users.service'; 7 | 8 | @Module({ 9 | providers: [UsersService], 10 | exports: [UsersService], 11 | controllers: [UsersController], 12 | imports: [MailerModule, OauthProvidersModule, TelemetryModule], 13 | }) 14 | export class UsersModule {} 15 | -------------------------------------------------------------------------------- /server/src/users/users.service.errors.ts: -------------------------------------------------------------------------------- 1 | export const RegisterUserErrors = ['UserAlreadyExists'] as const; 2 | export type RegisterUserError = (typeof RegisterUserErrors)[number]; 3 | 4 | export const LoginUserErrors = [ 5 | 'UserNotFound', 6 | 'InvalidPassword', 7 | 'UserDoesNotHavePasswordHashConfig', 8 | 'UserDoesNotHavePassword', 9 | ] as const; 10 | export type LoginUserError = (typeof LoginUserErrors)[number]; 11 | 12 | export const WhoAmIErrors = ['UserNotFound'] as const; 13 | export type WhoAmIError = (typeof WhoAmIErrors)[number]; 14 | 15 | export const OAuthLoginErrors = [ 16 | 'InvalidRedirectUri', 17 | 'InvalidState', 18 | 'InvalidCode', 19 | 'MissingClientSecret', 20 | 'MissingClientId', 21 | 'UnsupportedOAuthProvider', 22 | 'TokenRequestFailed', 23 | 'ImpossibleToGetUserInfo', 24 | ] as const; 25 | 26 | export type OAuthLoginError = (typeof OAuthLoginErrors)[number]; 27 | -------------------------------------------------------------------------------- /server/src/users/users.types.ts: -------------------------------------------------------------------------------- 1 | import { PasswordHashConfig } from '@prisma/client'; 2 | import { JWTPayload } from 'jose'; 3 | 4 | export type CreatePasswordHashConfig = 5 | | PasswordHashConfig 6 | | Omit; 7 | 8 | export type AccessTokenPayload = { 9 | sub: string; 10 | }; 11 | 12 | export const isAccessTokenPayload = ( 13 | payload: JWTPayload, 14 | ): payload is AccessTokenPayload => { 15 | return typeof payload.sub === 'string'; 16 | }; 17 | -------------------------------------------------------------------------------- /server/test/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { Test, TestingModule } from '@nestjs/testing'; 2 | import { INestApplication } from '@nestjs/common'; 3 | import * as request from 'supertest'; 4 | import { AppModule } from './../src/app.module'; 5 | 6 | describe('AppController (e2e)', () => { 7 | let app: INestApplication; 8 | 9 | beforeEach(async () => { 10 | const moduleFixture: TestingModule = await Test.createTestingModule({ 11 | imports: [AppModule], 12 | }).compile(); 13 | 14 | app = moduleFixture.createNestApplication(); 15 | await app.init(); 16 | }); 17 | 18 | it('/ (GET)', () => { 19 | return request(app.getHttpServer()) 20 | .get('/') 21 | .expect(200) 22 | .expect('Hello World!'); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /server/test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2021", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noImplicitAny": true, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": true, 19 | "noFallthroughCasesInSwitch": false, 20 | } 21 | } 22 | --------------------------------------------------------------------------------