├── .devcontainer ├── Dockerfile ├── devcontainer.json ├── docker-compose.yml └── startup.sh ├── .dockerignore ├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ └── JitAccess.yml ├── compliance │ └── inventory.yml ├── policies │ ├── branch-protection.yml │ └── jit.yml └── workflows │ ├── marketing-build.yml │ ├── marketing-builddeploy.yml │ ├── marketing-remove.yml │ ├── oagents-build-test-packages.yml │ ├── oagents-initialize-context.yml │ ├── oagents-publish-nuget.yml │ ├── oagents-release-nuget-packages.yml │ ├── support-center-build.yml │ └── support-center-builddeploy.yml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── LICENSE ├── LICENSE-CODE ├── OAgents.sln ├── README.md ├── SECURITY.md ├── docs └── FAQ.md ├── samples ├── WorkflowsApp │ ├── .env_example │ ├── Activities │ │ ├── ActivityProviders │ │ │ └── SemanticKernelSkillActivityProvider.cs │ │ └── SemanticKernel.cs │ ├── Config │ │ ├── KernelBuilder.cs │ │ ├── KernelSettings.cs │ │ └── PromptDefaults.cs │ ├── NuGet.Config │ ├── Pages │ │ └── _Host.cshtml │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── README.md │ ├── Skills │ │ ├── DevLeadPrompts.cs │ │ ├── Developer.cs │ │ ├── PMPrompts.cs │ │ └── SemanticFunctionConfig.cs │ ├── WorkflowsApp.csproj │ └── appsettings.Development.json ├── gh-flow │ ├── README.md │ ├── azure.yaml │ ├── components │ │ ├── pubsub.yaml │ │ └── statestore.yaml │ ├── docs │ │ ├── github-flow-getting-started.md │ │ └── images │ │ │ ├── github-sk-dev-team.png │ │ │ ├── new-codespace.png │ │ │ ├── overview.png │ │ │ └── solution-explorer.png │ ├── infra │ │ ├── abbreviations.json │ │ ├── app │ │ │ ├── db.bicep │ │ │ └── gh-flow.bicep │ │ ├── core │ │ │ ├── database │ │ │ │ ├── cosmos │ │ │ │ │ ├── cosmos-account.bicep │ │ │ │ │ └── sql │ │ │ │ │ │ ├── cosmos-sql-account.bicep │ │ │ │ │ │ ├── cosmos-sql-db.bicep │ │ │ │ │ │ ├── cosmos-sql-role-assign.bicep │ │ │ │ │ │ └── cosmos-sql-role-def.bicep │ │ │ │ ├── postgresql │ │ │ │ │ └── flexibleserver.bicep │ │ │ │ └── qdrant │ │ │ │ │ └── qdrant-aca.bicep │ │ │ ├── host │ │ │ │ ├── appservice-appsettings.bicep │ │ │ │ ├── appservice.bicep │ │ │ │ ├── appserviceplan.bicep │ │ │ │ ├── container-app-upsert.bicep │ │ │ │ ├── container-app.bicep │ │ │ │ ├── container-apps-environment.bicep │ │ │ │ ├── container-apps.bicep │ │ │ │ ├── container-registry.bicep │ │ │ │ └── functions.bicep │ │ │ ├── monitor │ │ │ │ ├── applicationinsights-dashboard.bicep │ │ │ │ ├── applicationinsights.bicep │ │ │ │ ├── loganalytics.bicep │ │ │ │ └── monitoring.bicep │ │ │ ├── security │ │ │ │ └── registry-access.bicep │ │ │ └── storage │ │ │ │ └── storage-account.bicep │ │ ├── main.bicep │ │ └── main.parameters.json │ └── src │ │ ├── Microsoft.AI.DevTeam.Dapr │ │ ├── Agents │ │ │ ├── Architect │ │ │ │ └── Architect.cs │ │ │ ├── AzureGenie.cs │ │ │ ├── Developer │ │ │ │ ├── Developer.cs │ │ │ │ └── DeveloperPrompts.cs │ │ │ ├── DeveloperLead │ │ │ │ ├── DevLeadPrompts.cs │ │ │ │ └── DeveloperLead.cs │ │ │ ├── Hubber.cs │ │ │ ├── ProductManager │ │ │ │ ├── PMPrompts.cs │ │ │ │ └── ProductManager.cs │ │ │ └── Sandbox.cs │ │ ├── Dockerfile │ │ ├── Events │ │ │ └── GithubFlowEventType.cs │ │ ├── Microsoft.AI.DevTeam.Dapr.csproj │ │ ├── Options │ │ │ ├── AzureOptions.cs │ │ │ ├── Consts.cs │ │ │ ├── GithubOptions.cs │ │ │ ├── OpenAIOptions.cs │ │ │ ├── QdrantOptions.cs │ │ │ └── ServiceOptions.cs │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Services │ │ │ ├── AzureService.cs │ │ │ ├── CodeAnalyzer.cs │ │ │ ├── GithubAuthService.cs │ │ │ ├── GithubService.cs │ │ │ └── GithubWebHookProcessor.cs │ │ ├── appsettings.azure.template.json │ │ └── appsettings.local.template.json │ │ ├── Microsoft.AI.DevTeam │ │ ├── Agents │ │ │ ├── Architect │ │ │ │ └── Architect.cs │ │ │ ├── AzureGenie.cs │ │ │ ├── Developer │ │ │ │ ├── Developer.cs │ │ │ │ └── DeveloperPrompts.cs │ │ │ ├── DeveloperLead │ │ │ │ ├── DevLeadPrompts.cs │ │ │ │ └── DeveloperLead.cs │ │ │ ├── Hubber.cs │ │ │ ├── ProductManager │ │ │ │ ├── PMPrompts.cs │ │ │ │ └── ProductManager.cs │ │ │ └── Sandbox.cs │ │ ├── Dockerfile │ │ ├── Events │ │ │ └── GithubFlowEventType.cs │ │ ├── Extensions │ │ │ └── ParseExtensions.cs │ │ ├── Microsoft.AI.DevTeam.csproj │ │ ├── Options │ │ │ ├── AzureOptions.cs │ │ │ ├── Consts.cs │ │ │ ├── GithubOptions.cs │ │ │ ├── OpenAIOptions.cs │ │ │ ├── QdrantOptions.cs │ │ │ └── ServiceOptions.cs │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── Services │ │ │ ├── AzureService.cs │ │ │ ├── CodeAnalyzer.cs │ │ │ ├── GithubAuthService.cs │ │ │ ├── GithubService.cs │ │ │ └── GithubWebHookProcessor.cs │ │ ├── appsettings.azure.template.json │ │ └── appsettings.local.template.json │ │ └── seed-memory │ │ ├── Dockerfile │ │ ├── Program.cs │ │ ├── README.md │ │ ├── azure-well-architected.pdf │ │ ├── config │ │ ├── KernelSettings.cs │ │ └── appsettings.template.json │ │ └── seed-memory.csproj ├── marketing │ ├── .gitignore │ ├── README.md │ ├── azure.yaml │ ├── infra │ │ ├── abbreviations.json │ │ ├── app │ │ │ ├── backend.bicep │ │ │ └── frontend.bicep │ │ ├── azd-hooks │ │ │ └── Write-MarketingEnvironmentVariables.ps1 │ │ ├── main.bicep │ │ ├── main.parameters.json │ │ ├── modules │ │ │ └── fetch-container-image.bicep │ │ └── shared │ │ │ ├── apps-env.bicep │ │ │ ├── dashboard-web.bicep │ │ │ ├── keyvault.bicep │ │ │ ├── monitoring.bicep │ │ │ └── registry.bicep │ ├── next-steps.md │ ├── readme-media │ │ ├── agents.png │ │ └── screenshot.png │ ├── run.ps1 │ ├── run.sh │ └── src │ │ ├── backend │ │ ├── .gitignore │ │ ├── Agents │ │ │ ├── Auditor │ │ │ │ ├── Auditor.cs │ │ │ │ ├── AuditorPrompts.cs │ │ │ │ └── AuditorState.cs │ │ │ ├── CommunityManager │ │ │ │ ├── CommunityManager.cs │ │ │ │ ├── CommunityManagerPrompts.cs │ │ │ │ └── CommunityManagerState.cs │ │ │ ├── GraphicDesigner │ │ │ │ ├── GraphicDesignedState.cs │ │ │ │ ├── GraphicDesigner.cs │ │ │ │ └── GraphicDesignerPrompts.cs │ │ │ ├── SignalR │ │ │ │ └── SignalR.cs │ │ │ └── Writer │ │ │ │ ├── IWritter.cs │ │ │ │ ├── Writer.cs │ │ │ │ ├── WriterPrompts.cs │ │ │ │ └── WriterState.cs │ │ ├── Controller │ │ │ └── Articles.cs │ │ ├── Dockerfile │ │ ├── Events │ │ │ └── EventTypes.cs │ │ ├── Marketing.csproj │ │ ├── Marketing.sln │ │ ├── Options │ │ │ ├── Consts.cs │ │ │ ├── OpenAIOptions.cs │ │ │ ├── QdrantOptions.cs │ │ │ └── Throw.cs │ │ ├── Program.cs │ │ ├── Properties │ │ │ └── launchSettings.json │ │ ├── SignalRHub │ │ │ ├── AgentTypes.cs │ │ │ ├── ArticleHub.cs │ │ │ ├── FrontEndMessage.cs │ │ │ ├── IArticleHub.cs │ │ │ ├── ISignalRService.cs │ │ │ ├── SignalRConnectionsDB.cs │ │ │ └── SignalRService.cs │ │ └── appsettings.local.template.json │ │ └── frontend │ │ ├── .dockeringnore │ │ ├── .env.template │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── .vscode │ │ └── launch.json │ │ ├── Dockerfile │ │ ├── README.MD │ │ ├── next.config.mjs │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── public │ │ └── static │ │ │ ├── background1.webp │ │ │ ├── check.png │ │ │ ├── face.jpg │ │ │ ├── face2.jpg │ │ │ ├── icons │ │ │ ├── docs.png │ │ │ ├── edge.png │ │ │ ├── pdf.png │ │ │ └── xslx.png │ │ │ └── x.png │ │ ├── src │ │ ├── app │ │ │ ├── icon.ico │ │ │ ├── layout.tsx │ │ │ ├── marketing │ │ │ │ ├── chat │ │ │ │ │ └── chat.tsx │ │ │ │ ├── community-manager │ │ │ │ │ └── community-manager.tsx │ │ │ │ ├── costs │ │ │ │ │ └── cost.tsx │ │ │ │ ├── docs │ │ │ │ │ └── docs.tsx │ │ │ │ ├── page.tsx │ │ │ │ └── stakeholders │ │ │ │ │ └── stakeholders.tsx │ │ │ ├── not-found.tsx │ │ │ └── page.tsx │ │ └── providers │ │ │ └── devtools │ │ │ └── index.tsx │ │ └── tsconfig.json └── support-center │ ├── README.md │ ├── azure.yaml │ ├── docs │ └── media │ │ ├── arch.png │ │ ├── screenshot.png │ │ └── supportcenter.png │ ├── infra │ ├── abbreviations.json │ ├── app │ │ ├── backend.bicep │ │ ├── db.bicep │ │ └── frontend.bicep │ ├── azd-hooks │ │ ├── load-envs.sh │ │ └── postprovision.ps1 │ ├── core │ │ ├── database │ │ │ ├── cosmos │ │ │ │ ├── cosmos-account.bicep │ │ │ │ └── sql │ │ │ │ │ ├── cosmos-sql-account.bicep │ │ │ │ │ ├── cosmos-sql-db.bicep │ │ │ │ │ ├── cosmos-sql-role-assign.bicep │ │ │ │ │ └── cosmos-sql-role-def.bicep │ │ │ ├── postgresql │ │ │ │ └── flexibleserver.bicep │ │ │ └── qdrant │ │ │ │ └── qdrant-aca.bicep │ │ ├── documentintelligence │ │ │ └── document-intelligence.bicep │ │ ├── search │ │ │ └── search.bicep │ │ └── storage │ │ │ └── storage-account.bicep │ ├── main.bicep │ ├── main.parameters.json │ ├── modules │ │ └── fetch-container-image.bicep │ └── shared │ │ ├── apps-env.bicep │ │ ├── dashboard-web.bicep │ │ ├── keyvault.bicep │ │ ├── monitoring.bicep │ │ └── registry.bicep │ ├── seed-invoice-memory │ ├── Dockerfile │ ├── MemoryProgram.cs │ ├── README.md │ ├── config │ │ ├── KernelSettings.cs │ │ └── appsettings.template.json │ └── seed-invoice-memory.csproj │ ├── seed-memory │ ├── Benefit_Options.pdf │ ├── Dockerfile │ ├── Northwind_Health_Plus_Benefits_Details.pdf │ ├── Northwind_Standard_Benefits_Details.pdf │ ├── PerksPlus.pdf │ ├── Program.cs │ ├── README.md │ ├── config │ │ ├── KernelSettings.cs │ │ └── appsettings.template.json │ ├── employee_handbook.pdf │ ├── role_library.pdf │ └── seed-memory.csproj │ └── src │ ├── backend │ ├── .dockerignore │ ├── Agents │ │ ├── Conversation │ │ │ ├── Conversation.cs │ │ │ ├── ConversationPrompts.cs │ │ │ └── ConversationState.cs │ │ ├── CustomerInfo │ │ │ ├── CustomerInfo.cs │ │ │ ├── CustomerInfoPrompts.cs │ │ │ └── CustomerInfoState.cs │ │ ├── Discount │ │ │ ├── Discount.cs │ │ │ └── DiscountState.cs │ │ ├── Dispatcher │ │ │ ├── Dispatcher.cs │ │ │ ├── DispatcherPrompts.cs │ │ │ └── DispatcherState.cs │ │ ├── Invoice │ │ │ ├── Invoice.cs │ │ │ ├── InvoicePrompts.cs │ │ │ └── InvoiceState.cs │ │ ├── QnA │ │ │ ├── QnA.cs │ │ │ ├── QnAPrompts.cs │ │ │ └── QnAState.cs │ │ └── SignalR │ │ │ └── SignalR.cs │ ├── AgentsConfigurationFactory │ │ ├── AgentConfiguration.cs │ │ ├── ConversationAgentConfiguration.cs │ │ ├── CustomerInfoAgentConfiguration.cs │ │ ├── DiscountAgentConfiguration.cs │ │ ├── DispatcherAgentConfiguration.cs │ │ ├── IAgentConfiguration.cs │ │ ├── InvoiceAgentConfiguration.cs │ │ ├── QnAAgentConfiguration.cs │ │ └── SignalRAgentConfiguration.cs │ ├── Attributes │ │ └── Choice.cs │ ├── Controllers │ │ └── Interactions.cs │ ├── Data │ │ ├── CosmosDb │ │ │ ├── CosmosDbRepository.cs │ │ │ ├── CustomerRepository.cs │ │ │ ├── Entities │ │ │ │ └── Customer.cs │ │ │ └── ICustomerRepository.cs │ │ └── Entities │ │ │ └── Entity.cs │ ├── Dockerfile │ ├── Events │ │ └── EventTypes.cs │ ├── Extensions │ │ ├── DictionaryExtension.cs │ │ ├── ObjectExtensions.cs │ │ ├── ServiceExtensions.cs │ │ ├── SupportCenterAgentExtensions.cs │ │ └── ValidationExtensions.cs │ ├── Options │ │ ├── AiSearchOptions.cs │ │ ├── Consts.cs │ │ ├── CosmosDbContainerOptions.cs │ │ ├── CosmosDbOptions.cs │ │ ├── OpenAIOptions.cs │ │ └── QdrantOptions.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── SemanticKernel │ │ ├── Extensions.cs │ │ └── Plugins │ │ │ └── CustomerPlugin │ │ │ └── CustomerData.cs │ ├── SignalRHub │ │ ├── AgentTypes.cs │ │ ├── FrontEndMessage.cs │ │ ├── ISignalRService.cs │ │ ├── ISupportCenterHub.cs │ │ ├── SignalRConnectionsDB.cs │ │ ├── SignalRService.cs │ │ └── SupportCenterHub.cs │ ├── SupportCenter.csproj │ ├── SupportCenter.sln │ ├── appsettings.local.template.Development.json │ └── appsettings.local.template.json │ └── frontend │ ├── .env.azureConfig │ ├── .env.localConfig │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── index.html │ ├── package.json │ ├── src │ ├── App.css │ ├── App.tsx │ ├── components │ │ ├── Login │ │ │ ├── Login.css │ │ │ └── Login.tsx │ │ ├── NavBar │ │ │ └── NavBar.tsx │ │ └── WelcomeHints │ │ │ ├── WelcomeHints.css │ │ │ └── WelcomeHints.tsx │ ├── index.css │ ├── main.tsx │ ├── models │ │ ├── Citation.ts │ │ ├── Configuration.ts │ │ ├── Conversation.ts │ │ ├── Knowledge.ts │ │ ├── KnowledgeDocument.ts │ │ └── Message.tsx │ ├── pages │ │ ├── PageStyles.ts │ │ └── chat │ │ │ ├── ChatPage.tsx │ │ │ └── components │ │ │ ├── ChatHistoryList │ │ │ ├── ChatHistoryList.css │ │ │ └── ChatHistoryList.tsx │ │ │ ├── ChatInputBox │ │ │ ├── ChatInputBox.css │ │ │ └── ChatInputBox.tsx │ │ │ └── ChatMessage │ │ │ ├── ChatMessage.css │ │ │ ├── ChatMessage.tsx │ │ │ └── MessageParser.tsx │ ├── services │ │ └── ChatService.ts │ ├── states │ │ ├── AppContext.ts │ │ └── ChatContext.ts │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── src ├── Oagents.Core ├── Abstractions │ ├── AgentState.cs │ ├── ChatHistoryItem.cs │ ├── ChatUserType.cs │ ├── Event.cs │ ├── IAgent.cs │ └── IAiAgent.cs └── Oagents.Core.csproj ├── Oagents.Dapr ├── Agent.cs ├── AiAgent.cs ├── IDaprAgent.cs └── Oagents.Dapr.csproj └── Oagents.Orleans ├── Agent.cs ├── AiAgent.cs ├── EventSurrogate.cs ├── Oagents.Orleans.csproj └── Resolvers.cs /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/dotnet:8.0 2 | # Install the xz-utils package 3 | # RUN apt-get update && apt-get install -y xz-utils ca-certificates curl gnupg 4 | 5 | # RUN curl -fsSL https://aka.ms/install-azd.sh | bash 6 | 7 | # RUN curl -sL https://aka.ms/DevTunnelCliInstall | bash -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | devcontainer: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | init: true 8 | volumes: 9 | - /var/run/docker.sock:/var/run/docker.sock 10 | - ..:/workspace:cached 11 | # Overrides default command so things don't shut down after the process ends. 12 | command: sleep infinity 13 | network_mode: service:qdrant 14 | depends_on: 15 | - qdrant 16 | qdrant: 17 | image: qdrant/qdrant 18 | ports: 19 | - 6333:6333 20 | redis: 21 | image: redis:alpine 22 | network_mode: service:qdrant 23 | zipkin: 24 | image: openzipkin/zipkin-slim:latest 25 | ports: 26 | - 9411:9411 27 | dapr-placement: 28 | image: "daprio/dapr" 29 | command: ["./placement", "--port", "50005"] 30 | network_mode: service:qdrant -------------------------------------------------------------------------------- /.devcontainer/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # curl -k https://localhost:8081/_explorer/emulator.pem > ~/emulatorcert.crt 4 | # sudo cp ~/emulatorcert.crt /usr/local/share/ca-certificates/ 5 | # sudo update-ca-certificates 6 | # sleep 10 7 | dotnet restore Microsoft.AI.Agents.sln 8 | 9 | dapr init --slim -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/compose* 19 | **/Dockerfile* 20 | **/node_modules 21 | **/npm-debug.log 22 | **/obj 23 | **/secrets.dev.yaml 24 | **/values.dev.yaml 25 | LICENSE 26 | README.md -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 4 11 | indent_style = space 12 | tab_width = 4 13 | 14 | #### .NET Coding Conventions #### 15 | 16 | # this. and Me. preferences 17 | dotnet_style_qualification_for_method = true 18 | 19 | #### Diagnostic configuration #### 20 | 21 | # SKEXP0001: Warning: SK Core is experimental 22 | dotnet_diagnostic.SKEXP0001.severity = none 23 | # SKEXP0020: Warning: SK Memory connectors are experimental 24 | dotnet_diagnostic.SKEXP0020.severity = none 25 | # SKEXP0010: Warning: SK OpenAI is experimental 26 | dotnet_diagnostic.SKEXP0010.severity = none 27 | # CA2007: Consider calling ConfigureAwait on the awaited task 28 | dotnet_diagnostic.CA2007.severity = none -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/JitAccess.yml: -------------------------------------------------------------------------------- 1 | name: Temporary administrator access request 2 | description: Request for temporary repository administrator access to this repository, a.k.a Just-in-Time (JIT) access. 3 | title: "JIT Request" 4 | labels: ["jit"] 5 | assignees: 6 | - gimsvc_microsoft 7 | - 8 | body: 9 | - type: markdown 10 | attributes: 11 | value: | 12 | :closed_lock_with_key: Permanent repository administrator access is not allowed as per Microsoft security policy. You can use this form to request for temporary administrator access to this repository. 13 | - type: textarea 14 | id: justification 15 | attributes: 16 | label: Justification 17 | description: Describe the actions that you will perform with your temporary administrator access. 18 | placeholder: I need to create secrets. 19 | validations: 20 | required: true 21 | - type: dropdown 22 | id: duration 23 | attributes: 24 | label: Duration (hours) 25 | description: How long do you need access for? The duration you select is in hours. 26 | options: 27 | - 1 28 | - 2 29 | -------------------------------------------------------------------------------- /.github/compliance/inventory.yml: -------------------------------------------------------------------------------- 1 | inventory: 2 | - source: DirectOwners 3 | items: 4 | - id: kopetan@microsoft.com 5 | - id: crgar@microsoft.com 6 | isProduction: false 7 | -------------------------------------------------------------------------------- /.github/policies/branch-protection.yml: -------------------------------------------------------------------------------- 1 | # Documentation for branch policy: https://aka.ms/gim/docs/policy/branch-protection 2 | 3 | name: Default branch protection policy 4 | description: Requires one reviewer for merges into main branch 5 | resource: repository 6 | where: 7 | configuration: 8 | branchProtectionRules: 9 | - branchNamePattern: "main" 10 | requiredApprovingReviewsCount: 1 11 | dismissStaleReviews: true 12 | -------------------------------------------------------------------------------- /.github/policies/jit.yml: -------------------------------------------------------------------------------- 1 | # Documentation for JIT policy: https://aka.ms/gim/docs/policy/jit 2 | 3 | # metadata 4 | id: id 5 | name: JIT_Access 6 | description: Policy for admin JIT for repos in this org 7 | 8 | # filters 9 | resource: repository 10 | 11 | # primitive configuration 12 | configuration: 13 | jitAccess: 14 | enabled: true 15 | maxHours: 2 16 | approvers: 17 | role: Maintain 18 | requestors: 19 | role: Write 20 | 21 | -------------------------------------------------------------------------------- /.github/workflows/marketing-build.yml: -------------------------------------------------------------------------------- 1 | name: '[Marketing Sample] Build sample application' 2 | run-name: '[PR #${{github.event.pull_request.number}}] [Marketing Sample] Build sample application' 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - samples/marketing/** 10 | - .github/workflows/marketing-build.yml 11 | - src/** 12 | pull_request: 13 | branches: 14 | - '**' 15 | paths: 16 | - samples/marketing/** 17 | - .github/workflows/marketing-build.yml 18 | - src/** 19 | workflow_dispatch: 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Build the backend 29 | run: | 30 | docker build -t marketing-backend -f samples/marketing/src/backend/Dockerfile . 31 | shell: pwsh 32 | 33 | - name: Build the frontend 34 | run: | 35 | cd samples/marketing/src/frontend/ 36 | docker build -t marketing-frontend . 37 | shell: pwsh -------------------------------------------------------------------------------- /.github/workflows/marketing-remove.yml: -------------------------------------------------------------------------------- 1 | name: '[Marketing Sample] Remove environment' 2 | run-name: '[PR #${{github.event.pull_request.number}}] [Marketing Sample] - Remove environment' 3 | 4 | on: 5 | workflow_dispatch: 6 | 7 | permissions: 8 | id-token: write 9 | contents: read 10 | 11 | defaults: 12 | run: 13 | shell: pwsh 14 | working-directory: ./samples/marketing 15 | 16 | jobs: 17 | deployment: 18 | # Environment is going to be used by GitHub to create the subject of the federated identity. 19 | environment: dev 20 | 21 | runs-on: ubuntu-latest 22 | env: 23 | AZURE_SUBSCRIPTION_ID: ${{ secrets.MARKETING_AZURE_SUBSCRIPTION_ID }} 24 | AZURE_ENV_NAME: ${{ secrets.MARKETING_AZURE_ENV_NAME }} 25 | AZURE_LOCATION: ${{ secrets.MARKETING_AZURE_LOCATION }} 26 | AZURE_TENANT_ID: ${{ secrets.MARKETING_AZURE_TENANT_ID }} 27 | AZURE_CLIENT_ID: ${{ secrets.MARKETING_AZURE_CLIENT_ID }} 28 | # AZURE_CREDENTIALS: ${{ secrets.MARKETING_AZURE_CREDENTIALS }} 29 | steps: 30 | - name: Checkout 31 | uses: actions/checkout@v4 32 | 33 | - name: Install azd 34 | uses: Azure/setup-azd@v1.0.0 35 | 36 | # https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect 37 | - name: Log in with Azure (Federated Credentials) 38 | if: ${{ env.AZURE_CLIENT_ID != '' }} 39 | run: | 40 | azd auth login ` 41 | --client-id "$Env:AZURE_CLIENT_ID" ` 42 | --federated-credential-provider "github" ` 43 | --tenant-id "$Env:AZURE_TENANT_ID" 44 | 45 | - name: Remove Infrastructure 46 | run: | 47 | azd down ` 48 | --no-prompt ` 49 | --force ` 50 | --purge ` 51 | --environment ${{ env.AZURE_ENV_NAME }} -------------------------------------------------------------------------------- /.github/workflows/oagents-build-test-packages.yml: -------------------------------------------------------------------------------- 1 | name: '[OAgents nuget] Build and test' 2 | 3 | on: 4 | workflow_call: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: Setup .NET 12 | uses: actions/setup-dotnet@v4 13 | with: 14 | dotnet-version: 8.0.x 15 | - name: Restore dependencies 16 | run: dotnet restore 17 | - name: Build 18 | run: dotnet build --no-restore 19 | - name: Test 20 | run: dotnet test --no-build --verbosity normal -------------------------------------------------------------------------------- /.github/workflows/oagents-initialize-context.yml: -------------------------------------------------------------------------------- 1 | name: '[OAgents nuget] Init context' 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | version_suffix: 7 | value: ${{ jobs.init.outputs.version_suffix }} 8 | 9 | jobs: 10 | init: 11 | runs-on: ubuntu-latest 12 | outputs: 13 | version_suffix: ${{ steps.set_version_suffix.outputs.VERSION_SUFFIX }} 14 | steps: 15 | - name: Set version suffix 16 | id: set_version_suffix 17 | run: echo "VERSION_SUFFIX=$(date +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT" -------------------------------------------------------------------------------- /.github/workflows/oagents-publish-nuget.yml: -------------------------------------------------------------------------------- 1 | name: '[OAgents nuget] Publish nuget package' 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | package-name: 7 | required: true 8 | type: string 9 | version-prefix: 10 | required: true 11 | type: string 12 | version-suffix: 13 | required: true 14 | type: string 15 | secrets: 16 | NUGET_API_KEY: 17 | required: true 18 | 19 | # 20 | jobs: 21 | build: 22 | 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Setup .NET 28 | uses: actions/setup-dotnet@v4 29 | with: 30 | dotnet-version: 8.0.x 31 | - name: Publish package 32 | run: | 33 | cd src/${{ inputs.package-name }} 34 | dotnet pack -o packages /p:PackageVersion=${{ inputs.version-prefix }}-alpha.${{ inputs.version-suffix }} 35 | dotnet nuget push $GITHUB_WORKSPACE/src/${{ inputs.package-name }}/packages/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json -------------------------------------------------------------------------------- /.github/workflows/oagents-release-nuget-packages.yml: -------------------------------------------------------------------------------- 1 | name: '[OAgents nuget] Publish all packages' 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'src/**' 7 | workflow_dispatch: 8 | 9 | permissions: 10 | id-token: write 11 | contents: read 12 | jobs: 13 | initialize-context: 14 | uses: ./.github/workflows/oagents-initialize-context.yml 15 | secrets: inherit 16 | build-test-packages: 17 | uses: ./.github/workflows/oagents-build-test-packages.yml 18 | needs: [initialize-context] 19 | secrets: inherit 20 | publish-core: 21 | # if: github.ref == 'refs/heads/main' # This job runs only if the push is to the main branch 22 | needs: [build-test-packages, initialize-context] 23 | uses: ./.github/workflows/oagents-publish-nuget.yml 24 | with: 25 | package-name: Oagents.Core 26 | version-prefix: 0.0.2 27 | version-suffix: ${{ needs.initialize-context.outputs.version_suffix }} 28 | secrets: inherit 29 | publish-orleans: 30 | # if: github.ref == 'refs/heads/main' # This job runs only if the push is to the main branch 31 | needs: [build-test-packages, initialize-context] 32 | uses: ./.github/workflows/oagents-publish-nuget.yml 33 | with: 34 | package-name: Oagents.Orleans 35 | version-prefix: 0.0.2 36 | version-suffix: ${{ needs.initialize-context.outputs.version_suffix }} 37 | secrets: inherit -------------------------------------------------------------------------------- /.github/workflows/support-center-build.yml: -------------------------------------------------------------------------------- 1 | name: '[Support Center Sample] Build sample application' 2 | run-name: '[PR #${{github.event.pull_request.number}}] [Support Center Sample] Build sample application' 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - samples/support-center/** 10 | - .github/workflows/support-center-build.yml 11 | - src/** 12 | pull_request: 13 | branches: 14 | - '**' 15 | paths: 16 | - samples/support-center/** 17 | - .github/workflows/support-center-build.yml 18 | - src/** 19 | workflow_dispatch: 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Build the backend 29 | run: | 30 | docker build -t support-center-backend -f samples/support-center/src/backend/Dockerfile . 31 | shell: pwsh 32 | 33 | - name: Build the frontend 34 | run: | 35 | cd samples/support-center/src/frontend/ 36 | docker build -t support-center-frontend . 37 | shell: pwsh -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "C#: Microsoft.AI.DevTeam.Dapr [Default Configuration] with Dapr", 5 | "type": "dotnet", 6 | "request": "launch", 7 | "projectPath": "${workspaceFolder}/samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Microsoft.AI.DevTeam.Dapr.csproj", 8 | "preLaunchTask": "dapr-debug", 9 | "postDebugTask": "daprd-down" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "dotnet.defaultSolution": "Microsoft.AI.Agents.sln", 3 | "debug.internalConsoleOptions": "neverOpen", 4 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "appId": "dev-agents", 6 | "grpcPort": 50001, 7 | "httpPort": 3500, 8 | "appPort": 5244, 9 | "componentsPath": "samples/gh-flow/components", 10 | "label": "dapr-debug", 11 | "type": "dapr" 12 | }, 13 | { 14 | "appId": "dev-agents", 15 | "label": "daprd-down", 16 | "type": "daprd-down" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /LICENSE-CODE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /docs/FAQ.md: -------------------------------------------------------------------------------- 1 | **Placeholder for FAQ document** 2 | 3 | More information about how this projects runs? 4 | 5 | This project leverages the devcontainer concept via your local system or you can use codespaces. Within this devcontainer/Codespaces you will have everything installed what you need. 6 | We are running mulitple containers. The devcontainer + Qdrant container + Cosmos emulator container. 7 | 8 | We also are leveraging Azure Services which you can easily deploy with Azure Developer CLI. To learn more about this: https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview 9 | 10 | Another concept we are using are Dev Tunnels. This basic explainiting is that Dev Tunnel will create a secure tunnel for your Webhook to send message to your local system or codespace enviroment. 11 | If you want to learn more about this: https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview 12 | 13 | Communication between agents: 14 | If you are running this fully locally we are using memory streams and local storage. If you are running this combined with Azure we are using Azure Event Hub for the communication between the agents (Can extended to use other solutions/services). 15 | 16 | Chathistory is being stored in CosmosDB (Can extended to use other solutions/services). Locally you can use the Cosmos DB emulator container or you can leverage an Azure CosmosDB deployment. 17 | 18 | -------------------------------------------------------------------------------- /samples/WorkflowsApp/.env_example: -------------------------------------------------------------------------------- 1 | 2 | # Replace with your own values 3 | export SERVICETYPE=AzureOpenAI 4 | export SERVICEID=gpt-4 5 | export DEPLOYMENTORMODELID=gpt-4 6 | export EMBEDDINGDEPLOYMENTORMODELID=text-embedding-ada-002 7 | export ENDPOINT="Error - you mus update your OpenAI Endpoint" 8 | export APIKEY="Error - you must update your OpenAPI or Azure API key" 9 | -------------------------------------------------------------------------------- /samples/WorkflowsApp/Config/KernelBuilder.cs: -------------------------------------------------------------------------------- 1 | using Azure; 2 | using Azure.AI.OpenAI; 3 | using Microsoft.Extensions.Http.Resilience; 4 | using Microsoft.SemanticKernel; 5 | 6 | internal static class KernelBuilder 7 | { 8 | /// 9 | /// Gets a semantic kernel instance 10 | /// 11 | /// Microsoft.SemanticKernel.IKernel 12 | public static Kernel BuildKernel() 13 | { 14 | var kernelSettings = KernelSettings.LoadSettings(); 15 | 16 | var clientOptions = new OpenAIClientOptions(); 17 | 18 | clientOptions.Retry.NetworkTimeout = TimeSpan.FromMinutes(5); 19 | 20 | var openAIClient = new OpenAIClient(new Uri(kernelSettings.Endpoint), new AzureKeyCredential(kernelSettings.ApiKey), clientOptions); 21 | var builder = Kernel.CreateBuilder(); 22 | 23 | builder.Services.AddLogging(c => c.AddConsole().AddDebug().SetMinimumLevel(LogLevel.Debug)); 24 | 25 | if (kernelSettings.ServiceType.Equals("AZUREOPENAI", StringComparison.OrdinalIgnoreCase)) 26 | { 27 | builder.Services.AddAzureOpenAIChatCompletion(kernelSettings.DeploymentOrModelId, openAIClient); 28 | } 29 | else 30 | { 31 | builder.Services.AddOpenAIChatCompletion(kernelSettings.DeploymentOrModelId, kernelSettings.ApiKey); 32 | } 33 | 34 | builder.Services.ConfigureHttpClientDefaults(c => 35 | { 36 | c.AddStandardResilienceHandler().Configure(o => 37 | { 38 | o.Retry.MaxRetryAttempts = 5; 39 | o.Retry.BackoffType = Polly.DelayBackoffType.Exponential; 40 | }); 41 | }); 42 | 43 | return builder.Build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/WorkflowsApp/Config/PromptDefaults.cs: -------------------------------------------------------------------------------- 1 | internal static class PromptDefaults 2 | { 3 | public const string SystemPrompt = @"You are fulfilling roles on a software development team. 4 | Provide a response to the following prompt, do not provide any additional output."; 5 | 6 | public const string UserPrompt = @"Let's build a ToDoList Application!"; 7 | 8 | } -------------------------------------------------------------------------------- /samples/WorkflowsApp/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /samples/WorkflowsApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:10492", 7 | "sslPort": 44312 8 | } 9 | }, 10 | "profiles": { 11 | "http": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "applicationUrl": "http://localhost:5181", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "https": { 21 | "commandName": "Project", 22 | "dotnetRunMessages": true, 23 | "launchBrowser": true, 24 | "applicationUrl": "https://localhost:7077;http://localhost:5181", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | }, 29 | "IIS Express": { 30 | "commandName": "IISExpress", 31 | "launchBrowser": true, 32 | "environmentVariables": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/WorkflowsApp/Skills/PMPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.SKDevTeam; 2 | public static class PM 3 | { 4 | public static SemanticFunctionConfig BootstrapProject = new SemanticFunctionConfig 5 | { 6 | PromptTemplate = """ 7 | Please write a bash script with the commands that would be required to generate applications as described in the following input. 8 | You may add comments to the script and the generated output but do not add any other text except the bash script. 9 | You may include commands to build the applications but do not run them. 10 | Do not include any git commands. 11 | Input: {{$input}} 12 | {{$wafContext}} 13 | """, 14 | Name = nameof(BootstrapProject), 15 | SkillName = nameof(PM), 16 | Description = "Bootstrap a new project", 17 | MaxTokens = 6500, 18 | Temperature = 0.0, 19 | TopP = 0.0, 20 | PPenalty = 0.0, 21 | FPenalty = 0.0 22 | }; 23 | public static SemanticFunctionConfig Readme = new SemanticFunctionConfig 24 | { 25 | PromptTemplate = """ 26 | You are a program manager on a software development team. You are working on an app described below. 27 | Based on the input below, and any dialog or other context, please output a raw README.MD markdown file documenting the main features of the app and the architecture or code organization. 28 | Do not describe how to create the application. 29 | Write the README as if it were documenting the features and architecture of the application. You may include instructions for how to run the application. 30 | Input: {{$input}} 31 | {{$wafContext}} 32 | """, 33 | Name = nameof(Readme), 34 | SkillName = nameof(PM), 35 | Description = "From a simple description output a README.md file for a GitHub repository.", 36 | MaxTokens = 6500, 37 | Temperature = 0.0, 38 | TopP = 0.0, 39 | PPenalty = 0.0, 40 | FPenalty = 0.0 41 | }; 42 | } -------------------------------------------------------------------------------- /samples/WorkflowsApp/Skills/SemanticFunctionConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.SKDevTeam; 2 | 3 | public class SemanticFunctionConfig 4 | { 5 | public string PromptTemplate { get; set; } 6 | public string Name { get; set; } 7 | public string SkillName { get; set; } 8 | public string Description { get; set; } 9 | public int MaxTokens { get; set; } 10 | public double Temperature { get; set; } 11 | public double TopP { get; set; } 12 | public double PPenalty { get; set; } 13 | public double FPenalty { get; set; } 14 | public static SemanticFunctionConfig ForSkillAndFunction(string skillName, string functionName) => 15 | (skillName, functionName) switch 16 | { 17 | (nameof(PM), nameof(PM.Readme)) => PM.Readme, 18 | (nameof(DevLead), nameof(DevLead.Plan)) => DevLead.Plan, 19 | (nameof(Developer), nameof(Developer.Implement)) => Developer.Implement, 20 | (nameof(Developer), nameof(Developer.Improve)) => Developer.Improve, 21 | (nameof(PM), nameof(PM.BootstrapProject)) => PM.BootstrapProject, 22 | _ => throw new ArgumentException($"Unable to find {skillName}.{functionName}") 23 | }; 24 | } -------------------------------------------------------------------------------- /samples/WorkflowsApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "Hosting": { 9 | "BasePath": "" 10 | }, 11 | "Shell": { 12 | "DisableAuthorization": false 13 | }, 14 | "Http": { 15 | "BaseUrl": "http://localhost:5181", 16 | "BasePath": "/api/workflows" 17 | }, 18 | "Backend": { 19 | "Url": "http://localhost:5181/elsa/api" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/gh-flow/azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | 3 | name: ai-dev-team 4 | services: 5 | gh-flow: 6 | project: "src/Microsoft.AI.DevTeam" 7 | language: csharp 8 | host: containerapp 9 | docker: 10 | context: ../../../../ 11 | -------------------------------------------------------------------------------- /samples/gh-flow/components/pubsub.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: agents-pubsub 5 | spec: 6 | type: pubsub.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" -------------------------------------------------------------------------------- /samples/gh-flow/components/statestore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: dapr.io/v1alpha1 2 | kind: Component 3 | metadata: 4 | name: agents-statestore 5 | spec: 6 | type: state.redis 7 | version: v1 8 | metadata: 9 | - name: redisHost 10 | value: localhost:6379 11 | - name: redisPassword 12 | value: "" 13 | - name: actorStateStore 14 | value: "true" 15 | -------------------------------------------------------------------------------- /samples/gh-flow/docs/images/github-sk-dev-team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/gh-flow/docs/images/github-sk-dev-team.png -------------------------------------------------------------------------------- /samples/gh-flow/docs/images/new-codespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/gh-flow/docs/images/new-codespace.png -------------------------------------------------------------------------------- /samples/gh-flow/docs/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/gh-flow/docs/images/overview.png -------------------------------------------------------------------------------- /samples/gh-flow/docs/images/solution-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/gh-flow/docs/images/solution-explorer.png -------------------------------------------------------------------------------- /samples/gh-flow/infra/abbreviations.json: -------------------------------------------------------------------------------- 1 | { 2 | "appManagedEnvironments": "cae-", 3 | "containerRegistryRegistries": "cr", 4 | "insightsComponents": "appi-", 5 | "operationalInsightsWorkspaces": "log-", 6 | "portalDashboards": "dash-", 7 | "resourcesResourceGroups": "rg-", 8 | "storageStorageAccounts": "st", 9 | "webServerFarms": "plan-", 10 | "webSitesFunctions": "func-", 11 | "appContainerApps": "ca-", 12 | "managedIdentityUserAssignedIdentities": "id-", 13 | "documentDBDatabaseAccounts":"cosmos-" 14 | } -------------------------------------------------------------------------------- /samples/gh-flow/infra/app/db.bicep: -------------------------------------------------------------------------------- 1 | param accountName string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param containers array = [ 6 | { 7 | name: 'reminders' 8 | id: 'reminders' 9 | partitionKey: '/id' 10 | } 11 | { 12 | name: 'persistence' 13 | id: 'persistence' 14 | partitionKey: '/id' 15 | } 16 | { 17 | name: 'clustering' 18 | id: 'clustering' 19 | partitionKey: '/id' 20 | } 21 | ] 22 | 23 | param databaseName string = '' 24 | param principalIds array = [] 25 | 26 | // Because databaseName is optional in main.bicep, we make sure the database name is set here. 27 | var defaultDatabaseName = 'Todo' 28 | var actualDatabaseName = !empty(databaseName) ? databaseName : defaultDatabaseName 29 | 30 | module cosmos '../core/database/cosmos/sql/cosmos-sql-db.bicep' = { 31 | name: 'cosmos-sql' 32 | params: { 33 | accountName: accountName 34 | location: location 35 | tags: tags 36 | containers: containers 37 | databaseName: actualDatabaseName 38 | principalIds: principalIds 39 | } 40 | } 41 | 42 | output accountName string = cosmos.outputs.accountName 43 | output connectionStringKey string = cosmos.outputs.connectionStringKey 44 | output databaseName string = cosmos.outputs.databaseName 45 | output endpoint string = cosmos.outputs.endpoint 46 | output roleDefinitionId string = cosmos.outputs.roleDefinitionId 47 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/database/cosmos/cosmos-account.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cosmos DB account.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' 7 | 8 | @allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) 9 | param kind string 10 | 11 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { 12 | name: name 13 | kind: kind 14 | location: location 15 | tags: tags 16 | properties: { 17 | consistencyPolicy: { defaultConsistencyLevel: 'Session' } 18 | locations: [ 19 | { 20 | locationName: location 21 | failoverPriority: 0 22 | isZoneRedundant: false 23 | } 24 | ] 25 | databaseAccountOfferType: 'Standard' 26 | enableAutomaticFailover: false 27 | enableMultipleWriteLocations: false 28 | apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.0' } : {} 29 | capabilities: [ { name: 'EnableServerless' } ] 30 | } 31 | } 32 | 33 | 34 | output connectionStringKey string = connectionStringKey 35 | output endpoint string = cosmos.properties.documentEndpoint 36 | output id string = cosmos.id 37 | output name string = cosmos.name 38 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/database/cosmos/sql/cosmos-sql-account.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cosmos DB for NoSQL account.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | module cosmos '../../cosmos/cosmos-account.bicep' = { 7 | name: 'cosmos-account' 8 | params: { 9 | name: name 10 | location: location 11 | tags: tags 12 | kind: 'GlobalDocumentDB' 13 | } 14 | } 15 | 16 | output connectionStringKey string = cosmos.outputs.connectionStringKey 17 | output endpoint string = cosmos.outputs.endpoint 18 | output id string = cosmos.outputs.id 19 | output name string = cosmos.outputs.name 20 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a SQL role assignment under an Azure Cosmos DB account.' 2 | param accountName string 3 | 4 | param roleDefinitionId string 5 | param principalId string = '' 6 | 7 | resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { 8 | parent: cosmos 9 | name: guid(roleDefinitionId, principalId, cosmos.id) 10 | properties: { 11 | principalId: principalId 12 | roleDefinitionId: roleDefinitionId 13 | scope: cosmos.id 14 | } 15 | } 16 | 17 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { 18 | name: accountName 19 | } 20 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a SQL role definition under an Azure Cosmos DB account.' 2 | param accountName string 3 | 4 | resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { 5 | parent: cosmos 6 | name: guid(cosmos.id, accountName, 'sql-role') 7 | properties: { 8 | assignableScopes: [ 9 | cosmos.id 10 | ] 11 | permissions: [ 12 | { 13 | dataActions: [ 14 | 'Microsoft.DocumentDB/databaseAccounts/readMetadata' 15 | 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' 16 | 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' 17 | ] 18 | notDataActions: [] 19 | } 20 | ] 21 | roleName: 'Reader Writer' 22 | type: 'CustomRole' 23 | } 24 | } 25 | 26 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { 27 | name: accountName 28 | } 29 | 30 | output id string = roleDefinition.id 31 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/database/postgresql/flexibleserver.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param sku object 6 | param storage object 7 | param administratorLogin string 8 | @secure() 9 | param administratorLoginPassword string 10 | param databaseNames array = [] 11 | param allowAzureIPsFirewall bool = false 12 | param allowAllIPsFirewall bool = false 13 | param allowedSingleIPs array = [] 14 | 15 | // PostgreSQL version 16 | param version string 17 | 18 | // Latest official version 2022-12-01 does not have Bicep types available 19 | resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = { 20 | location: location 21 | tags: tags 22 | name: name 23 | sku: sku 24 | properties: { 25 | version: version 26 | administratorLogin: administratorLogin 27 | administratorLoginPassword: administratorLoginPassword 28 | storage: storage 29 | highAvailability: { 30 | mode: 'Disabled' 31 | } 32 | } 33 | 34 | resource database 'databases' = [for name in databaseNames: { 35 | name: name 36 | }] 37 | 38 | resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) { 39 | name: 'allow-all-IPs' 40 | properties: { 41 | startIpAddress: '0.0.0.0' 42 | endIpAddress: '255.255.255.255' 43 | } 44 | } 45 | 46 | resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) { 47 | name: 'allow-all-azure-internal-IPs' 48 | properties: { 49 | startIpAddress: '0.0.0.0' 50 | endIpAddress: '0.0.0.0' 51 | } 52 | } 53 | 54 | resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: { 55 | name: 'allow-single-${replace(ip, '.', '')}' 56 | properties: { 57 | startIpAddress: ip 58 | endIpAddress: ip 59 | } 60 | }] 61 | 62 | } 63 | 64 | output POSTGRES_DOMAIN_NAME string = postgresServer.properties.fullyQualifiedDomainName 65 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/host/appservice-appsettings.bicep: -------------------------------------------------------------------------------- 1 | @description('The name of the app service resource within the current resource group scope') 2 | param name string 3 | 4 | @description('The app settings to be applied to the app service') 5 | @secure() 6 | param appSettings object 7 | 8 | resource appService 'Microsoft.Web/sites@2022-03-01' existing = { 9 | name: name 10 | } 11 | 12 | resource settings 'Microsoft.Web/sites/config@2022-03-01' = { 13 | name: 'appsettings' 14 | parent: appService 15 | properties: appSettings 16 | } 17 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/host/appserviceplan.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param kind string = '' 6 | param reserved bool = true 7 | param sku object 8 | 9 | resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { 10 | name: name 11 | location: location 12 | tags: tags 13 | sku: sku 14 | kind: kind 15 | properties: { 16 | reserved: reserved 17 | } 18 | } 19 | 20 | output id string = appServicePlan.id 21 | output name string = appServicePlan.name 22 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/host/container-apps-environment.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @description('Name of the Application Insights resource') 6 | param applicationInsightsName string = '' 7 | 8 | @description('Specifies if Dapr is enabled') 9 | param daprEnabled bool = false 10 | 11 | @description('Name of the Log Analytics workspace') 12 | param logAnalyticsWorkspaceName string 13 | 14 | resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-04-01-preview' = { 15 | name: name 16 | location: location 17 | tags: tags 18 | properties: { 19 | appLogsConfiguration: { 20 | destination: 'log-analytics' 21 | logAnalyticsConfiguration: { 22 | customerId: logAnalyticsWorkspace.properties.customerId 23 | sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey 24 | } 25 | } 26 | daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : '' 27 | } 28 | } 29 | 30 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { 31 | name: logAnalyticsWorkspaceName 32 | } 33 | 34 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (daprEnabled && !empty(applicationInsightsName)) { 35 | name: applicationInsightsName 36 | } 37 | 38 | output defaultDomain string = containerAppsEnvironment.properties.defaultDomain 39 | output id string = containerAppsEnvironment.id 40 | output name string = containerAppsEnvironment.name 41 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/host/container-apps.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param containerAppsEnvironmentName string 6 | param containerRegistryName string 7 | param containerRegistryResourceGroupName string = '' 8 | param logAnalyticsWorkspaceName string 9 | param applicationInsightsName string = '' 10 | 11 | module containerAppsEnvironment 'container-apps-environment.bicep' = { 12 | name: '${name}-container-apps-environment' 13 | params: { 14 | name: containerAppsEnvironmentName 15 | location: location 16 | tags: tags 17 | logAnalyticsWorkspaceName: logAnalyticsWorkspaceName 18 | applicationInsightsName: applicationInsightsName 19 | } 20 | } 21 | 22 | module containerRegistry 'container-registry.bicep' = { 23 | name: '${name}-container-registry' 24 | scope: !empty(containerRegistryResourceGroupName) ? resourceGroup(containerRegistryResourceGroupName) : resourceGroup() 25 | params: { 26 | name: containerRegistryName 27 | location: location 28 | tags: tags 29 | } 30 | } 31 | 32 | output defaultDomain string = containerAppsEnvironment.outputs.defaultDomain 33 | output environmentName string = containerAppsEnvironment.outputs.name 34 | output environmentId string = containerAppsEnvironment.outputs.id 35 | 36 | output registryLoginServer string = containerRegistry.outputs.loginServer 37 | output registryName string = containerRegistry.outputs.name 38 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/monitor/applicationinsights.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param dashboardName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | param includeDashboard bool = true 6 | param logAnalyticsWorkspaceId string 7 | 8 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | kind: 'web' 13 | properties: { 14 | Application_Type: 'web' 15 | WorkspaceResourceId: logAnalyticsWorkspaceId 16 | } 17 | } 18 | 19 | module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = if (includeDashboard) { 20 | name: 'application-insights-dashboard' 21 | params: { 22 | name: dashboardName 23 | location: location 24 | applicationInsightsName: applicationInsights.name 25 | } 26 | } 27 | 28 | output connectionString string = applicationInsights.properties.ConnectionString 29 | output instrumentationKey string = applicationInsights.properties.InstrumentationKey 30 | output name string = applicationInsights.name 31 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/monitor/loganalytics.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { 6 | name: name 7 | location: location 8 | tags: tags 9 | properties: any({ 10 | retentionInDays: 30 11 | features: { 12 | searchVersion: 1 13 | } 14 | sku: { 15 | name: 'PerGB2018' 16 | } 17 | }) 18 | } 19 | 20 | output id string = logAnalytics.id 21 | output name string = logAnalytics.name 22 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/monitor/monitoring.bicep: -------------------------------------------------------------------------------- 1 | param logAnalyticsName string 2 | param applicationInsightsName string 3 | param applicationInsightsDashboardName string 4 | param location string = resourceGroup().location 5 | param tags object = {} 6 | param includeDashboard bool = true 7 | 8 | module logAnalytics 'loganalytics.bicep' = { 9 | name: 'loganalytics' 10 | params: { 11 | name: logAnalyticsName 12 | location: location 13 | tags: tags 14 | } 15 | } 16 | 17 | module applicationInsights 'applicationinsights.bicep' = { 18 | name: 'applicationinsights' 19 | params: { 20 | name: applicationInsightsName 21 | location: location 22 | tags: tags 23 | dashboardName: applicationInsightsDashboardName 24 | includeDashboard: includeDashboard 25 | logAnalyticsWorkspaceId: logAnalytics.outputs.id 26 | } 27 | } 28 | 29 | output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString 30 | output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey 31 | output applicationInsightsName string = applicationInsights.outputs.name 32 | output logAnalyticsWorkspaceId string = logAnalytics.outputs.id 33 | output logAnalyticsWorkspaceName string = logAnalytics.outputs.name 34 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/core/security/registry-access.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' 2 | param containerRegistryName string 3 | param principalId string 4 | 5 | var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') 6 | 7 | resource aksAcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = { 8 | scope: containerRegistry // Use when specifying a scope that is different than the deployment scope 9 | name: guid(subscription().id, resourceGroup().id, principalId, acrPullRole) 10 | properties: { 11 | roleDefinitionId: acrPullRole 12 | principalType: 'ServicePrincipal' 13 | principalId: principalId 14 | } 15 | } 16 | 17 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { 18 | name: containerRegistryName 19 | } 20 | -------------------------------------------------------------------------------- /samples/gh-flow/infra/main.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "environmentName": { 6 | "value": "${AZURE_ENV_NAME}" 7 | }, 8 | "location": { 9 | "value": "${AZURE_LOCATION}" 10 | }, 11 | "githubAppKey": { 12 | "value": "${GH_APP_KEY}" 13 | }, 14 | "githubAppId": { 15 | "value": "${GH_APP_ID}" 16 | }, 17 | "githubAppInstallationId": { 18 | "value": "${GH_APP_INST_ID}" 19 | }, 20 | "openAIServiceType": { 21 | "value": "${OAI_SERVICE_TYPE}" 22 | }, 23 | "openAIServiceId": { 24 | "value": "${OAI_SERVICE_ID}" 25 | }, 26 | "openAIDeploymentId": { 27 | "value": "${OAI_DEPLOYMENT_ID}" 28 | }, 29 | "openAIEmbeddingId": { 30 | "value": "${OAI_EMBEDDING_ID}" 31 | }, 32 | "openAIEndpoint": { 33 | "value": "${OAI_ENDPOINT}" 34 | }, 35 | "openAIKey": { 36 | "value": "${OAI_KEY}" 37 | }, 38 | "principalId": { 39 | "value": "${AZURE_PRINCIPAL_ID}" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Agents/Architect/Architect.cs: -------------------------------------------------------------------------------- 1 | using Dapr.Actors.Runtime; 2 | using Dapr.Client; 3 | using Microsoft.AI.Agents.Abstractions; 4 | using Microsoft.AI.Agents.Dapr; 5 | using Microsoft.SemanticKernel; 6 | using Microsoft.SemanticKernel.Memory; 7 | 8 | namespace Microsoft.AI.DevTeam.Dapr; 9 | 10 | 11 | // The architect has Org+Repo scope and is holding the knowledge of the high level architecture of the project 12 | public class Architect : AiAgent,IDaprAgent 13 | { 14 | public Architect(ActorHost host, DaprClient client, ISemanticTextMemory memory, Kernel kernel) 15 | : base(host, client, memory, kernel) 16 | { 17 | } 18 | 19 | public override Task HandleEvent(Event item) 20 | { 21 | return Task.CompletedTask; 22 | } 23 | } 24 | 25 | public class ArchitectState 26 | { 27 | public string FilesTree { get; set; } 28 | public string HighLevelArchitecture { get; set; } 29 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Agents/ProductManager/PMPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.DevTeam.Dapr; 2 | public static class PMSkills 3 | { 4 | public static string BootstrapProject = """ 5 | Please write a bash script with the commands that would be required to generate applications as described in the following input. 6 | You may add comments to the script and the generated output but do not add any other text except the bash script. 7 | You may include commands to build the applications but do not run them. 8 | Do not include any git commands. 9 | Input: {{$input}} 10 | {{$waf}} 11 | """; 12 | public static string Readme = """ 13 | You are a program manager on a software development team. You are working on an app described below. 14 | Based on the input below, and any dialog or other context, please output a raw README.MD markdown file documenting the main features of the app and the architecture or code organization. 15 | Do not describe how to create the application. 16 | Write the README as if it were documenting the features and architecture of the application. You may include instructions for how to run the application. 17 | Input: {{$input}} 18 | {{$waf}} 19 | """; 20 | 21 | public static string Explain = """ 22 | You are a Product Manager. 23 | Please explain the code that is in the input below. You can include references or documentation links in your explanation. 24 | Also where appropriate please output a list of keywords to describe the code or its capabilities. 25 | example: 26 | Keywords: Azure, networking, security, authentication 27 | 28 | If the code's purpose is not clear output an error: 29 | Error: The model could not determine the purpose of the code. 30 | 31 | -- 32 | Input: {{$input}} 33 | """; 34 | } 35 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base 2 | WORKDIR /app 3 | EXPOSE 5274 4 | EXPOSE 11111 5 | EXPOSE 30000 6 | 7 | ENV ASPNETCORE_URLS=http://+:5274 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 10 | ARG configuration=Release 11 | COPY . . 12 | RUN dotnet restore "src/apps/gh-flow/gh-flow.csproj" 13 | WORKDIR "/src/apps/gh-flow" 14 | RUN dotnet build "gh-flow.csproj" -c $configuration -o /app/build 15 | 16 | FROM build AS publish 17 | ARG configuration=Release 18 | RUN dotnet publish "gh-flow.csproj" -c $configuration -o /app/publish 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "gh-flow.dll"] -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/AzureOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam.Dapr; 4 | public class AzureOptions 5 | { 6 | [Required] 7 | public string SubscriptionId { get; set; } 8 | [Required] 9 | public string Location { get; set; } 10 | [Required] 11 | public string ContainerInstancesResourceGroup { get; set; } 12 | [Required] 13 | public string FilesShareName { get; set; } 14 | [Required] 15 | public string FilesAccountName { get; set; } 16 | [Required] 17 | public string FilesAccountKey { get; set; } 18 | [Required] 19 | public string SandboxImage { get; set; } 20 | public string ManagedIdentity { get; set; } 21 | public string CosmosConnectionString { get; set; } 22 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/Consts.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.DevTeam.Dapr; 2 | 3 | public static class Consts 4 | { 5 | public const string MainTopic = "DevPersonas"; 6 | public const string PubSub = "agents-pubsub"; 7 | public const string AppId = "dev-agents"; 8 | } 9 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/GithubOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam.Dapr; 4 | public class GithubOptions 5 | { 6 | [Required] 7 | public string AppKey { get; set; } 8 | [Required] 9 | public int AppId { get; set; } 10 | [Required] 11 | public long InstallationId { get; set; } 12 | [Required] 13 | public string WebhookSecret { get; set; } 14 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/OpenAIOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam.Dapr; 4 | public class OpenAIOptions 5 | { 6 | [Required] 7 | public string ServiceType { get; set; } 8 | [Required] 9 | public string ServiceId { get; set; } 10 | [Required] 11 | public string DeploymentOrModelId { get; set; } 12 | [Required] 13 | public string EmbeddingDeploymentOrModelId { get; set; } 14 | [Required] 15 | public string Endpoint { get; set; } 16 | [Required] 17 | public string ApiKey { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/QdrantOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam.Dapr; 4 | public class QdrantOptions 5 | { 6 | [Required] 7 | public string Endpoint { get; set; } 8 | [Required] 9 | public int VectorSize { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Options/ServiceOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam.Dapr; 4 | public class ServiceOptions 5 | { 6 | private string _ingesterUrl; 7 | 8 | [Required] 9 | public string IngesterUrl { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:59668", 8 | "sslPort": 44354 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5244", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7227;http://localhost:5244", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/Services/CodeAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace Microsoft.AI.DevTeam.Dapr; 6 | 7 | public interface IAnalyzeCode 8 | { 9 | Task> Analyze(string content); 10 | } 11 | public class CodeAnalyzer : IAnalyzeCode 12 | { 13 | private readonly ServiceOptions _serviceOptions; 14 | private readonly HttpClient _httpClient; 15 | private readonly ILogger _logger; 16 | 17 | public CodeAnalyzer(IOptions serviceOptions, HttpClient httpClient, ILogger logger) 18 | { 19 | _serviceOptions = serviceOptions.Value; 20 | _httpClient = httpClient; 21 | _logger = logger; 22 | _httpClient.BaseAddress = new Uri(_serviceOptions.IngesterUrl); 23 | 24 | } 25 | public async Task> Analyze(string content) 26 | { 27 | try 28 | { 29 | var request = new CodeAnalysisRequest { Content = content }; 30 | var body = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); 31 | var response = await _httpClient.PostAsync("api/AnalyzeCode", body); 32 | var stringResult = await response.Content.ReadAsStringAsync(); 33 | var result = JsonSerializer.Deserialize>(stringResult); 34 | return result; 35 | } 36 | catch (Exception ex) 37 | { 38 | _logger.LogError(ex, "Error analyzing code"); 39 | return Enumerable.Empty(); 40 | } 41 | } 42 | } 43 | 44 | public class CodeAnalysisRequest 45 | { 46 | public string Content { get; set; } 47 | } 48 | 49 | public class CodeAnalysis 50 | { 51 | public string Meaning { get; set; } 52 | public string CodeBlock { get; set; } 53 | } 54 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/appsettings.azure.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Information", 6 | "Orleans.Streams": "Information" 7 | } 8 | }, 9 | "ApplicationInsights": { 10 | "ConnectionString": "" 11 | }, 12 | "AllowedHosts": "*", 13 | "SANDBOX_IMAGE" : "mcr.microsoft.com/dotnet/sdk:7.0", 14 | "GithubOptions" : { 15 | "AppKey": "", 16 | "AppId": "", 17 | "InstallationId": "", 18 | "WebhookSecret": "" 19 | }, 20 | "AzureOptions" : { 21 | "SubscriptionId":"", 22 | "Location":"", 23 | "ContainerInstancesResourceGroup":"", 24 | "FilesShareName":"", 25 | "FilesAccountName":"", 26 | "FilesAccountKey":"", 27 | "SandboxImage" : "mcr.microsoft.com/dotnet/sdk:7.0", 28 | "ManagedIdentity": "" 29 | }, 30 | "OpenAIOptions" : { 31 | "ServiceType":"AzureOpenAI", 32 | "ServiceId":"gpt-4", 33 | "DeploymentOrModelId":"gpt-4", 34 | "EmbeddingDeploymentOrModelId":"text-embedding-ada-002", 35 | "Endpoint":"", 36 | "ApiKey":"" 37 | }, 38 | "QdrantOptions" : { 39 | "Endpoint" : "http://qdrant:6333", 40 | "VectorSize" : "1536" 41 | }, 42 | "ServiceOptions" : { 43 | "IngesterUrl" : "http://localhost:7071" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam.Dapr/appsettings.local.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Information", 6 | "Orleans.Streams": "Information" 7 | } 8 | }, 9 | "ApplicationInsights": { 10 | "ConnectionString": "" 11 | }, 12 | "AllowedHosts": "*", 13 | "SANDBOX_IMAGE" : "mcr.microsoft.com/dotnet/sdk:7.0", 14 | "GithubOptions" : { 15 | "AppKey": "", 16 | "AppId": "", 17 | "InstallationId": "", 18 | "WebhookSecret": "" 19 | }, 20 | "AzureOptions" : { 21 | "SubscriptionId":"", 22 | "Location":"", 23 | "ContainerInstancesResourceGroup":"", 24 | "FilesShareName":"", 25 | "FilesAccountName":"", 26 | "FilesAccountKey":"", 27 | "SandboxImage" : "mcr.microsoft.com/dotnet/sdk:7.0", 28 | "ManagedIdentity": "" 29 | }, 30 | "OpenAIOptions" : { 31 | "ServiceType":"AzureOpenAI", 32 | "ServiceId":"gpt-4", 33 | "DeploymentOrModelId":"gpt-4", 34 | "EmbeddingDeploymentOrModelId":"text-embedding-ada-002", 35 | "Endpoint":"", 36 | "ApiKey":"" 37 | }, 38 | "QdrantOptions" : { 39 | "Endpoint" : "http://qdrant:6333", 40 | "VectorSize" : "1536" 41 | }, 42 | "ServiceOptions" : { 43 | "IngesterUrl" : "http://localhost:7071" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Agents/Architect/Architect.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | using Microsoft.AI.Agents.Orleans; 3 | using Microsoft.SemanticKernel; 4 | using Microsoft.SemanticKernel.Memory; 5 | using Orleans.Runtime; 6 | 7 | namespace Microsoft.AI.DevTeam; 8 | 9 | 10 | // The architect has Org+Repo scope and is holding the knowledge of the high level architecture of the project 11 | [ImplicitStreamSubscription(Consts.MainNamespace)] 12 | public class Architect : AiAgent 13 | { 14 | protected override string Namespace => Consts.MainNamespace; 15 | public Architect([PersistentState("state", "messages")] IPersistentState> state, ISemanticTextMemory memory, Kernel kernel) 16 | : base(state, memory, kernel) 17 | { 18 | } 19 | 20 | public override Task HandleEvent(Event item) 21 | { 22 | return Task.CompletedTask; 23 | } 24 | } 25 | 26 | [GenerateSerializer] 27 | public class ArchitectState 28 | { 29 | [Id(0)] 30 | public string FilesTree { get; set; } 31 | [Id(1)] 32 | public string HighLevelArchitecture { get; set; } 33 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Agents/ProductManager/PMPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.DevTeam; 2 | public static class PMSkills 3 | { 4 | public static string BootstrapProject = """ 5 | Please write a bash script with the commands that would be required to generate applications as described in the following input. 6 | You may add comments to the script and the generated output but do not add any other text except the bash script. 7 | You may include commands to build the applications but do not run them. 8 | Do not include any git commands. 9 | Input: {{$input}} 10 | {{$waf}} 11 | """; 12 | public static string Readme = """ 13 | You are a program manager on a software development team. You are working on an app described below. 14 | Based on the input below, and any dialog or other context, please output a raw README.MD markdown file documenting the main features of the app and the architecture or code organization. 15 | Do not describe how to create the application. 16 | Write the README as if it were documenting the features and architecture of the application. You may include instructions for how to run the application. 17 | Input: {{$input}} 18 | {{$waf}} 19 | """; 20 | 21 | public static string Explain = """ 22 | You are a Product Manager. 23 | Please explain the code that is in the input below. You can include references or documentation links in your explanation. 24 | Also where appropriate please output a list of keywords to describe the code or its capabilities. 25 | example: 26 | Keywords: Azure, networking, security, authentication 27 | 28 | If the code's purpose is not clear output an error: 29 | Error: The model could not determine the purpose of the code. 30 | 31 | -- 32 | Input: {{$input}} 33 | """; 34 | } 35 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | WORKDIR /app 3 | EXPOSE 5274 4 | EXPOSE 11111 5 | EXPOSE 30000 6 | 7 | ENV ASPNETCORE_URLS=http://+:5274 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG configuration=Release 11 | COPY . . 12 | RUN dotnet restore "samples/gh-flow/src/Microsoft.AI.DevTeam/Microsoft.AI.DevTeam.csproj" 13 | WORKDIR "samples/gh-flow/src/Microsoft.AI.DevTeam" 14 | RUN dotnet build "Microsoft.AI.DevTeam.csproj" -c $configuration -o /app/build 15 | 16 | FROM build AS publish 17 | ARG configuration=Release 18 | RUN dotnet publish "Microsoft.AI.DevTeam.csproj" -c $configuration -o /app/publish 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "Microsoft.AI.DevTeam.dll"] -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Extensions/ParseExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.DevTeam.Extensions 2 | { 3 | public static class ParseExtensions 4 | { 5 | public static long TryParseLong(this Dictionary data, string key) 6 | { 7 | ArgumentNullException.ThrowIfNull(data); 8 | 9 | if (data.TryGetValue(key, out string? value) && !string.IsNullOrEmpty(value) && long.TryParse(value, out var result)) 10 | { 11 | return result; 12 | } 13 | return default; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/AzureOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam; 4 | 5 | public class AzureOptions 6 | { 7 | [Required] 8 | public string SubscriptionId { get; set; } 9 | [Required] 10 | public string Location { get; set; } 11 | [Required] 12 | public string ContainerInstancesResourceGroup { get; set; } 13 | [Required] 14 | public string FilesShareName { get; set; } 15 | [Required] 16 | public string FilesAccountName { get; set; } 17 | [Required] 18 | public string FilesAccountKey { get; set; } 19 | [Required] 20 | public string SandboxImage { get; set; } 21 | public string ManagedIdentity { get; set; } 22 | public string CosmosConnectionString { get; set; } 23 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/Consts.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.DevTeam; 2 | 3 | public static class Consts 4 | { 5 | public const string MainNamespace = "DevPersonas"; 6 | } 7 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/GithubOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam; 4 | public class GithubOptions 5 | { 6 | [Required] 7 | public string AppKey { get; set; } 8 | [Required] 9 | public int AppId { get; set; } 10 | [Required] 11 | public long InstallationId { get; set; } 12 | [Required] 13 | public string WebhookSecret { get; set; } 14 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/OpenAIOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam; 4 | public class OpenAIOptions 5 | { 6 | [Required] 7 | public string ServiceType { get; set; } 8 | [Required] 9 | public string ServiceId { get; set; } 10 | [Required] 11 | public string DeploymentOrModelId { get; set; } 12 | [Required] 13 | public string EmbeddingDeploymentOrModelId { get; set; } 14 | [Required] 15 | public string Endpoint { get; set; } 16 | [Required] 17 | public string ApiKey { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/QdrantOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam; 4 | public class QdrantOptions 5 | { 6 | [Required] 7 | public string Endpoint { get; set; } 8 | [Required] 9 | public int VectorSize { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Options/ServiceOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Microsoft.AI.DevTeam; 4 | public class ServiceOptions 5 | { 6 | private string _ingesterUrl; 7 | 8 | [Required] 9 | public string IngesterUrl { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:59668", 8 | "sslPort": 44354 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5244", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "https": { 22 | "commandName": "Project", 23 | "dotnetRunMessages": true, 24 | "launchBrowser": true, 25 | "applicationUrl": "https://localhost:7227;http://localhost:5244", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | }, 30 | "IIS Express": { 31 | "commandName": "IISExpress", 32 | "launchBrowser": true, 33 | "environmentVariables": { 34 | "ASPNETCORE_ENVIRONMENT": "Development" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/Services/CodeAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace Microsoft.AI.DevTeam; 6 | 7 | public interface IAnalyzeCode 8 | { 9 | Task> Analyze(string content); 10 | } 11 | public class CodeAnalyzer : IAnalyzeCode 12 | { 13 | private readonly ServiceOptions _serviceOptions; 14 | private readonly HttpClient _httpClient; 15 | private readonly ILogger _logger; 16 | 17 | public CodeAnalyzer(IOptions serviceOptions, HttpClient httpClient, ILogger logger) 18 | { 19 | _serviceOptions = serviceOptions.Value; 20 | _httpClient = httpClient; 21 | _logger = logger; 22 | _httpClient.BaseAddress = new Uri(_serviceOptions.IngesterUrl); 23 | 24 | } 25 | public async Task> Analyze(string content) 26 | { 27 | try 28 | { 29 | var request = new CodeAnalysisRequest { Content = content }; 30 | var body = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"); 31 | var response = await _httpClient.PostAsync("api/AnalyzeCode", body); 32 | var stringResult = await response.Content.ReadAsStringAsync(); 33 | var result = JsonSerializer.Deserialize>(stringResult); 34 | return result; 35 | } 36 | catch (Exception ex) 37 | { 38 | _logger.LogError(ex, "Error analyzing code"); 39 | return Enumerable.Empty(); 40 | } 41 | } 42 | } 43 | 44 | public class CodeAnalysisRequest 45 | { 46 | public string Content { get; set; } 47 | } 48 | 49 | public class CodeAnalysis 50 | { 51 | public string Meaning { get; set; } 52 | public string CodeBlock { get; set; } 53 | } 54 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/appsettings.azure.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Information", 6 | "Orleans.Streams": "Information" 7 | } 8 | }, 9 | "ApplicationInsights": { 10 | "ConnectionString": "" 11 | }, 12 | "AllowedHosts": "*", 13 | "SANDBOX_IMAGE" : "mcr.microsoft.com/dotnet/sdk:7.0", 14 | "GithubOptions" : { 15 | "AppKey": "", 16 | "AppId": "", 17 | "InstallationId": "", 18 | "WebhookSecret": "" 19 | }, 20 | "AzureOptions" : { 21 | "SubscriptionId":"", 22 | "Location":"", 23 | "ContainerInstancesResourceGroup":"", 24 | "FilesShareName":"", 25 | "FilesAccountName":"", 26 | "FilesAccountKey":"", 27 | "SandboxImage" : "mcr.microsoft.com/dotnet/sdk:7.0", 28 | "ManagedIdentity": "", 29 | "CosmosConnectionString":"" 30 | }, 31 | "OpenAIOptions" : { 32 | "ServiceType":"AzureOpenAI", 33 | "ServiceId":"gpt-4", 34 | "DeploymentOrModelId":"gpt-4", 35 | "EmbeddingDeploymentOrModelId":"text-embedding-ada-002", 36 | "Endpoint":"", 37 | "ApiKey":"" 38 | }, 39 | "QdrantOptions" : { 40 | "Endpoint" : "http://qdrant:6333", 41 | "VectorSize" : "1536" 42 | }, 43 | "ServiceOptions" : { 44 | "IngesterUrl" : "http://localhost:7071" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /samples/gh-flow/src/Microsoft.AI.DevTeam/appsettings.local.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Information", 6 | "Orleans.Streams": "Information" 7 | } 8 | }, 9 | "ApplicationInsights": { 10 | "ConnectionString": "" 11 | }, 12 | "AllowedHosts": "*", 13 | "SANDBOX_IMAGE" : "mcr.microsoft.com/dotnet/sdk:7.0", 14 | "GithubOptions" : { 15 | "AppKey": "", 16 | "AppId": "", 17 | "InstallationId": "", 18 | "WebhookSecret": "" 19 | }, 20 | "AzureOptions" : { 21 | "SubscriptionId":"", 22 | "Location":"", 23 | "ContainerInstancesResourceGroup":"", 24 | "FilesShareName":"", 25 | "FilesAccountName":"", 26 | "FilesAccountKey":"", 27 | "SandboxImage" : "mcr.microsoft.com/dotnet/sdk:7.0", 28 | "ManagedIdentity": "" 29 | }, 30 | "OpenAIOptions" : { 31 | "ServiceType":"AzureOpenAI", 32 | "ServiceId":"gpt-4", 33 | "DeploymentOrModelId":"gpt-4", 34 | "EmbeddingDeploymentOrModelId":"text-embedding-ada-002", 35 | "Endpoint":"", 36 | "ApiKey":"" 37 | }, 38 | "QdrantOptions" : { 39 | "Endpoint" : "http://qdrant:6333", 40 | "VectorSize" : "1536" 41 | }, 42 | "ServiceOptions" : { 43 | "IngesterUrl" : "http://localhost:7071" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/gh-flow/src/seed-memory/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base 2 | WORKDIR /app 3 | 4 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 5 | WORKDIR /src 6 | COPY ["util/seed-memory/seed-memory.csproj", "util/seed-memory/"] 7 | RUN dotnet restore "util/seed-memory/seed-memory.csproj" 8 | COPY . . 9 | WORKDIR "/src/util/seed-memory" 10 | RUN dotnet build "seed-memory.csproj" -c Release -o /app/build 11 | 12 | FROM build AS publish 13 | RUN dotnet publish "seed-memory.csproj" -c Release -o /app/publish /p:UseAppHost=false 14 | 15 | FROM base AS final 16 | WORKDIR /app 17 | COPY --from=publish /app/publish . 18 | ENTRYPOINT ["dotnet", "seed-memory.dll"] 19 | -------------------------------------------------------------------------------- /samples/gh-flow/src/seed-memory/README.md: -------------------------------------------------------------------------------- 1 | # TODO -------------------------------------------------------------------------------- /samples/gh-flow/src/seed-memory/azure-well-architected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/gh-flow/src/seed-memory/azure-well-architected.pdf -------------------------------------------------------------------------------- /samples/gh-flow/src/seed-memory/config/appsettings.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceType": "AzureOpenAI", 3 | "serviceId": "", 4 | "deploymentOrModelId": "", 5 | "embeddingDeploymentOrModelId": "", 6 | "endpoint": "", 7 | "apiKey": "", 8 | "qdrantEndpoint": "" 9 | } -------------------------------------------------------------------------------- /samples/gh-flow/src/seed-memory/seed-memory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | waf_import 7 | enable 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | PreserveNewest 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /samples/marketing/.gitignore: -------------------------------------------------------------------------------- 1 | .azure 2 | -------------------------------------------------------------------------------- /samples/marketing/README.md: -------------------------------------------------------------------------------- 1 | # [In progress] Marketing Sample application 2 | 3 | This is a demo application that showcase the different features of the AI Agent framework. 4 | There are five agents in this application that control the different areas of the UI autonomously. 5 | 6 | The agents are designed to be able to interact with each other and the user to achieve their goals. 7 | To do that each agent has 8 | 9 | ![Agents](readme-media/screenshot.png) 10 | 11 | ![Agents](readme-media/agents.png) 12 | 13 | ## Requirements to run locally 14 | ### Frontend 15 | The latest version of Node.js and npm 16 | 17 | ### Backend 18 | Visual Studio or Visual Studio code and the latest version of dotnet 19 | 20 | ## Running with azd 21 | To run the application with azd, you need to have the azd cli installed. You can install it following the instructions here: 22 | 23 | https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux 24 | 25 | 26 | 27 | Then you can run the following command to start the application: 28 | ```powers 29 | 30 | ## How to run the application locally 31 | 32 | Execute Run.ps1. IF you are missing the config file the script will create an empty one for you and ask you to fill it out. 33 | ``` 34 | .\run.ps1 35 | ``` 36 | 37 | ## How to debug the application locally 38 | To debug the backend, you can simply open the solution in Visual Studio, and press F5 to start debugging. 39 | Remember to copy `appsettings.local.template.json` to `appsettings.json` and fill out the values.

40 | The frontend is a NodeJS React application. You can debug it using Visual Studio code. -------------------------------------------------------------------------------- /samples/marketing/azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | 3 | name: marketing 4 | metadata: 5 | template: azd-init@1.8.2 6 | hooks: 7 | postprovision: 8 | interactive: false 9 | shell: pwsh 10 | run: infra/azd-hooks/Write-MarketingEnvironmentVariables.ps1 11 | services: 12 | backend: 13 | project: "src/backend" 14 | host: containerapp 15 | language: dotnet 16 | docker: 17 | path: Dockerfile 18 | context: ../../../../ 19 | frontend: 20 | project: "src/frontend" 21 | host: containerapp 22 | language: ts 23 | dist: build 24 | docker: 25 | path: Dockerfile 26 | -------------------------------------------------------------------------------- /samples/marketing/infra/azd-hooks/Write-MarketingEnvironmentVariables.ps1: -------------------------------------------------------------------------------- 1 | 2 | # Make environment variables out of all outputs from bicep file 3 | Write-Verbose "---Setting environment variables..." -Verbose 4 | azd env get-values | % { 5 | $name,$value = $_.Split('=') 6 | 7 | #Value is quoted, so remove quotes 8 | $value = $value.Replace('"','') 9 | 10 | [System.Environment]::SetEnvironmentVariable($name,$value) 11 | Write-Verbose "Variable '$name' set to '$value'" -Verbose 12 | } 13 | Write-Verbose "---Done setting environment variables" -Verbose 14 | 15 | $templateFileName = ".env.template" 16 | $prodEnvFileName = ".env" 17 | 18 | # Replace the backend endpoint in the frontend .env file 19 | Write-Verbose "---Updating '$prodEnvFileName' file updated with backend endpoint..." -Verbose 20 | pushd src/frontend 21 | if (-not (Test-Path -Path $templateFileName)) { 22 | Write-Error "The file '$templateFileName' does not exist." 23 | } 24 | Copy-Item -Path $templateFileName -Destination $prodEnvFileName 25 | (Get-Content $prodEnvFileName) -replace '', $env:AZURE_BACKEND_URI | Set-Content $prodEnvFileName 26 | popd 27 | Write-Verbose "---Done updating '$prodEnvFileName' file updated with backend endpoint..." -Verbose 28 | -------------------------------------------------------------------------------- /samples/marketing/infra/modules/fetch-container-image.bicep: -------------------------------------------------------------------------------- 1 | param exists bool 2 | param name string 3 | 4 | resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { 5 | name: name 6 | } 7 | 8 | output containers array = exists ? existingApp.properties.template.containers : [] 9 | -------------------------------------------------------------------------------- /samples/marketing/infra/shared/apps-env.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param logAnalyticsWorkspaceName string 6 | param applicationInsightsName string = '' 7 | 8 | resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-10-01' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | properties: { 13 | appLogsConfiguration: { 14 | destination: 'log-analytics' 15 | logAnalyticsConfiguration: { 16 | customerId: logAnalyticsWorkspace.properties.customerId 17 | sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey 18 | } 19 | } 20 | daprAIConnectionString: applicationInsights.properties.ConnectionString 21 | } 22 | } 23 | 24 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { 25 | name: logAnalyticsWorkspaceName 26 | } 27 | 28 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { 29 | name: applicationInsightsName 30 | } 31 | 32 | output name string = containerAppsEnvironment.name 33 | output domain string = containerAppsEnvironment.properties.defaultDomain 34 | -------------------------------------------------------------------------------- /samples/marketing/infra/shared/keyvault.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @description('Service principal that should be granted read access to the KeyVault. If unset, no service principal is granted access by default') 6 | param principalId string = '' 7 | 8 | var defaultAccessPolicies = !empty(principalId) ? [ 9 | { 10 | objectId: principalId 11 | permissions: { secrets: [ 'get', 'list' ] } 12 | tenantId: subscription().tenantId 13 | } 14 | ] : [] 15 | 16 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 17 | name: name 18 | location: location 19 | tags: tags 20 | properties: { 21 | tenantId: subscription().tenantId 22 | sku: { family: 'A', name: 'standard' } 23 | enabledForTemplateDeployment: true 24 | accessPolicies: union(defaultAccessPolicies, [ 25 | // define access policies here 26 | ]) 27 | } 28 | } 29 | 30 | output endpoint string = keyVault.properties.vaultUri 31 | output name string = keyVault.name 32 | -------------------------------------------------------------------------------- /samples/marketing/infra/shared/monitoring.bicep: -------------------------------------------------------------------------------- 1 | param logAnalyticsName string 2 | param applicationInsightsName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { 7 | name: logAnalyticsName 8 | location: location 9 | tags: tags 10 | properties: any({ 11 | retentionInDays: 30 12 | features: { 13 | searchVersion: 1 14 | } 15 | sku: { 16 | name: 'PerGB2018' 17 | } 18 | }) 19 | } 20 | 21 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 22 | name: applicationInsightsName 23 | location: location 24 | tags: tags 25 | kind: 'web' 26 | properties: { 27 | Application_Type: 'web' 28 | WorkspaceResourceId: logAnalytics.id 29 | } 30 | } 31 | 32 | output applicationInsightsName string = applicationInsights.name 33 | output logAnalyticsWorkspaceId string = logAnalytics.id 34 | output logAnalyticsWorkspaceName string = logAnalytics.name 35 | -------------------------------------------------------------------------------- /samples/marketing/infra/shared/registry.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param adminUserEnabled bool = true 6 | param anonymousPullEnabled bool = false 7 | param dataEndpointEnabled bool = false 8 | param encryption object = { 9 | status: 'disabled' 10 | } 11 | param networkRuleBypassOptions string = 'AzureServices' 12 | param publicNetworkAccess string = 'Enabled' 13 | param sku object = { 14 | name: 'Standard' 15 | } 16 | param zoneRedundancy string = 'Disabled' 17 | 18 | // 2023-01-01-preview needed for anonymousPullEnabled 19 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = { 20 | name: name 21 | location: location 22 | tags: tags 23 | sku: sku 24 | properties: { 25 | adminUserEnabled: adminUserEnabled 26 | anonymousPullEnabled: anonymousPullEnabled 27 | dataEndpointEnabled: dataEndpointEnabled 28 | encryption: encryption 29 | networkRuleBypassOptions: networkRuleBypassOptions 30 | publicNetworkAccess: publicNetworkAccess 31 | zoneRedundancy: zoneRedundancy 32 | } 33 | } 34 | 35 | output loginServer string = containerRegistry.properties.loginServer 36 | output name string = containerRegistry.name 37 | -------------------------------------------------------------------------------- /samples/marketing/readme-media/agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/readme-media/agents.png -------------------------------------------------------------------------------- /samples/marketing/readme-media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/readme-media/screenshot.png -------------------------------------------------------------------------------- /samples/marketing/run.ps1: -------------------------------------------------------------------------------- 1 | if(Test-Path src/backend/appsettings.json) { 2 | Write-Verbose "appsettings.json already exists" -Verbose 3 | } else { 4 | Copy-Item src/backend/appsettings.local.template.json src/backend/appsettings.json 5 | Write-Verbose "appsettings.json created" -Verbose 6 | } 7 | 8 | if((Get-Content .\src\backend\appsettings.json -Raw | Select-String "") -ne $null) { 9 | Write-Error "Please update the appsettings.json file with the correct values" -ErrorAction Stop 10 | } 11 | 12 | $backendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/backend/; dotnet run' 13 | $frontendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/frontend/; npm run dev' -------------------------------------------------------------------------------- /samples/marketing/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -f src/backend/appsettings.json ]; then 4 | echo "appsettings.json already exists" 5 | else 6 | cp src/backend/appsettings.local.template.json src/backend/appsettings.json 7 | echo "appsettings.json created" 8 | fi 9 | 10 | if grep -q "" src/backend/appsettings.local.template.json; then 11 | echo "Please update the appsettings.json file with the correct values" >&2 12 | exit 1 13 | fi 14 | 15 | gnome-terminal -- bash -c "cd src/backend/ && dotnet run; exec bash" 16 | gnome-terminal -- bash -c "cd src/frontend/ && npm run dev; exec bash" -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/Auditor/AuditorPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | public static class AuditorPrompts 4 | { 5 | public static string AuditText = """ 6 | You are an Auditor in a Marketing team 7 | Audit the text bello and make sure we do not give discounts larger than 10% 8 | If the text talks about a larger than 10% discount, reply with a message to the user saying that the discount is too large, and by company policy we are not allowed. 9 | If the message says who wrote it, add that information in the response as well 10 | In any other case, reply with NOTFORME 11 | --- 12 | Input: {{$input}} 13 | --- 14 | """; 15 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/Auditor/AuditorState.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | [GenerateSerializer] 4 | public class AuditorState 5 | { 6 | [Id(0)] 7 | public string Article { get; set; } 8 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | public static class CommunityManagerPrompts 4 | { 5 | public static string WritePost = """ 6 | You are a Marketing community manager writer. 7 | If the request from the user is to write a post to promote a new product, or if it is specifically talking to you (community manager) 8 | then you should write a post based on the user request 9 | Your writings are going to be posted on Tweeter. So be informal, friendly and add some hashtags and emojis. 10 | Remember, the tweet cannot be longer than 280 characters. 11 | If the request was not intedend for you. reply with " 12 | --- 13 | Input: {{$input}} 14 | --- 15 | """; 16 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerState.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | [GenerateSerializer] 4 | public class CommunityManagerState 5 | { 6 | [Id(0)] 7 | public string WrittenSocialMediaPost { get; set; } 8 | public string Article { get; set; } 9 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesignedState.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | [GenerateSerializer] 4 | public class GraphicDesignerState 5 | { 6 | [Id(0)] 7 | public string imageUrl { get; set; } 8 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesignerPrompts.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Marketing.Agents; 3 | public static class GraphicDesignerPrompts 4 | { 5 | public static string GenerateImage = """ 6 | You are a Marketing community manager graphic designer. 7 | Bellow is a campaing that you need to create a image for. 8 | Create an image of maximum 500x500 pixels that could be use in social medias as a marketing iamge. 9 | Only answer if the user is asking for an image to be created or if the user is asking for a new compaing 10 | Input: {{$input}} 11 | """; 12 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/Writer/IWritter.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | public interface IWriter : IGrainWithStringKey 3 | { 4 | Task GetArticle(); 5 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/Writer/WriterPrompts.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Marketing.Agents; 3 | public static class WriterPrompts 4 | { 5 | public static string Write = """ 6 | This is a multi agent app. You are a Marketing Campaign writer Agent. 7 | If the request is not for you, answer with . 8 | If the request is about writing or modifying an existing campaing, then you should write a campain based on the user request. 9 | Write up to three paragraphs to promote the product the user is asking for. 10 | Bellow are a series of inputs from the user that you can use. 11 | If the input talks about twitter or images, dismiss it and return 12 | Input: {{$input}} 13 | """; 14 | 15 | public static string Adjust = """ 16 | This is a multi agent app. You are a Marketing Campaign writer Agent. 17 | If the request is not for you, answer with . 18 | If the request is about writing or modifying an existing campaing, then you should write a campain based on the user request. 19 | The campaign is not compliant with the company policy, and you need to adjust it. This is the message from the automatic auditor agent regarding what is wrong with the original campaing 20 | --- 21 | Input: {{$input}} 22 | --- 23 | Return only the new campaign text but adjusted to the auditor request 24 | """; 25 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Agents/Writer/WriterState.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Agents; 2 | 3 | [GenerateSerializer] 4 | public class WriterState 5 | { 6 | [Id(0)] 7 | public string WrittenArticle { get; set; } 8 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | WORKDIR /app 3 | EXPOSE 5274 4 | EXPOSE 5244 5 | EXPOSE 11111 6 | EXPOSE 30000 7 | 8 | ENV ASPNETCORE_URLS=http://+:5244 9 | 10 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 11 | ARG configuration=Debug 12 | COPY . . 13 | RUN dotnet restore "samples/marketing/src/backend/Marketing.csproj" 14 | WORKDIR "samples/marketing/src/backend" 15 | RUN dotnet build "Marketing.csproj" -c $configuration -o /app/build 16 | 17 | FROM build AS publish 18 | ARG configuration=Debug 19 | RUN dotnet publish "Marketing.csproj" -c $configuration -o /app/publish 20 | 21 | FROM base AS final 22 | WORKDIR /app 23 | COPY --from=publish /app/publish . 24 | ENTRYPOINT ["dotnet", "Marketing.dll"] -------------------------------------------------------------------------------- /samples/marketing/src/backend/Events/EventTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Events; 2 | 3 | public enum EventTypes 4 | { 5 | UserChatInput, 6 | ArticleCreated, 7 | UserConnected, 8 | GraphicDesignCreated, 9 | SocialMediaPostCreated, 10 | AuditText, 11 | AuditorAlert 12 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Marketing.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Marketing", "Marketing.csproj", "{491A6E2F-A0D0-4723-80A2-B0F60091E39D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {491A6E2F-A0D0-4723-80A2-B0F60091E39D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {491A6E2F-A0D0-4723-80A2-B0F60091E39D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {491A6E2F-A0D0-4723-80A2-B0F60091E39D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {491A6E2F-A0D0-4723-80A2-B0F60091E39D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A6288EF9-5DDB-45A9-AA9A-EB9FDB18D82F} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/Options/Consts.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.Options; 2 | 3 | public static class Consts 4 | { 5 | public const string OrleansNamespace = "DevPersonas"; 6 | } 7 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/Options/OpenAIOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Marketing.Options; 4 | 5 | public class OpenAIOptions 6 | { 7 | // Embeddings 8 | [Required] 9 | public string EmbeddingsEndpoint { get; set; } 10 | [Required] 11 | public string EmbeddingsApiKey { get; set; } 12 | [Required] 13 | public string EmbeddingsDeploymentOrModelId { get; set; } 14 | 15 | // Chat 16 | [Required] 17 | public string ChatEndpoint { get; set; } 18 | [Required] 19 | public string ChatApiKey { get; set; } 20 | [Required] 21 | public string ChatDeploymentOrModelId { get; set; } 22 | 23 | // TextToImage 24 | [Required] 25 | public string ImageEndpoint { get; set; } 26 | [Required] 27 | public string ImageApiKey { get; set; } 28 | // When using OpenAI, this is not required. 29 | public string ImageDeploymentOrModelId { get; set; } 30 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Options/QdrantOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace Marketing.Options; 4 | public class QdrantOptions 5 | { 6 | [Required] 7 | public string Endpoint { get; set; } 8 | [Required] 9 | public int VectorSize { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/marketing/src/backend/Options/Throw.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing 2 | { 3 | public static class Throw 4 | { 5 | public static void IfNullOrEmpty(string paramName, string value) 6 | { 7 | if (string.IsNullOrEmpty(value)) 8 | { 9 | throw new ArgumentNullException(paramName); 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:59668", 8 | "sslPort": 44354 9 | } 10 | }, 11 | "profiles": { 12 | "http": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "applicationUrl": "http://localhost:5244", 17 | "launchUrl": "dashboard", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "https": { 23 | "commandName": "Project", 24 | "dotnetRunMessages": true, 25 | "launchBrowser": true, 26 | "applicationUrl": "https://localhost:7227;http://localhost:5244", 27 | "launchUrl": "dashboard", 28 | "environmentVariables": { 29 | "ASPNETCORE_ENVIRONMENT": "Development" 30 | } 31 | }, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/AgentTypes.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.SignalRHub; 2 | 3 | public enum AgentTypes 4 | { 5 | Chat, 6 | CommunityManager, 7 | GraphicDesigner, 8 | Auditor, 9 | Accountant, 10 | Librarian 11 | } 12 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/FrontEndMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.SignalRHub; 2 | 3 | public class FrontEndMessage 4 | { 5 | public string UserId { get; set; } 6 | public string Message { get; set; } 7 | public string Agent { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/IArticleHub.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.SignalRHub; 2 | 3 | public interface IArticleHub 4 | { 5 | public Task ConnectToAgent(string UserId); 6 | 7 | public Task ChatMessage(FrontEndMessage frontEndMessage, IClusterClient clusterClient); 8 | 9 | public Task SendMessageToSpecificClient(string userId, string message); 10 | } 11 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/ISignalRService.cs: -------------------------------------------------------------------------------- 1 | namespace Marketing.SignalRHub; 2 | public interface ISignalRService 3 | { 4 | Task SendMessageToSpecificClient(string userId, string message, AgentTypes agentType); 5 | } 6 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/SignalRConnectionsDB.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace Marketing.SignalRHub; 4 | public static class SignalRConnectionsDB 5 | { 6 | public static ConcurrentDictionary ConnectionIdByUser { get; } = new ConcurrentDictionary(); 7 | public static ConcurrentDictionary AllConnections { get; } = new ConcurrentDictionary(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/SignalRHub/SignalRService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Collections.Concurrent; 3 | 4 | namespace Marketing.SignalRHub; 5 | 6 | public class SignalRService : ISignalRService 7 | { 8 | private readonly IHubContext _hubContext; 9 | public SignalRService(IHubContext hubContext) 10 | { 11 | _hubContext = hubContext; 12 | } 13 | 14 | public async Task SendMessageToSpecificClient(string userId, string message, AgentTypes agentType) 15 | { 16 | var connectionId = SignalRConnectionsDB.ConnectionIdByUser[userId]; 17 | var frontEndMessage = new FrontEndMessage() 18 | { 19 | UserId = userId, 20 | Message = message, 21 | Agent = agentType.ToString() 22 | }; 23 | await _hubContext.Clients.Client(connectionId).SendAsync("ReceiveMessage", frontEndMessage); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/marketing/src/backend/appsettings.local.template.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Information", 7 | "Microsoft.AspNetCore.SignalR": "Debug", 8 | "Microsoft.AspNetCore.Http.Connections": "Debug" 9 | } 10 | }, 11 | 12 | "ApplicationInsights": { 13 | "ConnectionString": "InstrumentationKey=;IngestionEndpoint=https://.applicationinsights.azure.com/" 14 | }, 15 | 16 | "AllowedHosts": "*", 17 | 18 | "OpenAIOptions": { 19 | "ChatDeploymentOrModelId": "gpt-4-32", 20 | "ChatEndpoint": "https://.openai.azure.com/", 21 | "ChatApiKey": "", 22 | "EmbeddingsDeploymentOrModelId": "text-embedding-ada-002", 23 | "EmbeddingsEndpoint": "https://.openai.azure.com/", 24 | "EmbeddingsApiKey": "", 25 | "ImageDeploymentOrModelId":"dalle3", 26 | "ImageEndpoint": "https://.openai.azure.com/", 27 | "ImageApiKey": "" 28 | }, 29 | 30 | "QdrantOptions": { 31 | "Endpoint": "http://qdrant:6333", 32 | "VectorSize": "1536" 33 | } 34 | } -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.dockeringnore: -------------------------------------------------------------------------------- 1 | # Front end needs the environment variables at build time 2 | !.env -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.env.template: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_BACKEND_URI= -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | /.infra/ 2 | 3 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 4 | 5 | # dependencies 6 | /node_modules 7 | /.pnp 8 | .pnp.js 9 | .yarn/install-state.gz 10 | 11 | # testing 12 | /coverage 13 | 14 | # next.js 15 | /.next/ 16 | /out/ 17 | 18 | # production 19 | /build 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | 25 | # debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | # local env files 31 | .env*.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # typescript 37 | *.tsbuildinfo 38 | next-env.d.ts -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Next.js: debug server-side", 6 | "type": "node-terminal", 7 | "request": "launch", 8 | "command": "npm run dev" 9 | }, 10 | { 11 | "name": "Next.js: debug client-side", 12 | "type": "chrome", 13 | "request": "launch", 14 | "url": "http://localhost:3000" 15 | }, 16 | { 17 | "name": "Next.js: debug full stack", 18 | "type": "node-terminal", 19 | "request": "launch", 20 | "command": "npm run dev", 21 | "serverReadyAction": { 22 | "pattern": "- Local:.+(https?://.+)", 23 | "uriFormat": "%s", 24 | "action": "debugWithChrome" 25 | } 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /samples/marketing/src/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM refinedev/node:18 AS base 2 | 3 | FROM base AS deps 4 | RUN apk add --no-cache libc6-compat 5 | COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ 6 | RUN \ 7 | if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ 8 | elif [ -f package-lock.json ]; then npm ci; \ 9 | elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ 10 | else echo "Lockfile not found." && exit 1; \ 11 | fi 12 | 13 | FROM base AS builder 14 | ENV NEXT_TELEMETRY_DEBUG=1 15 | COPY --from=deps /app/refine/node_modules ./node_modules 16 | COPY . . 17 | RUN npm run build 18 | 19 | FROM base AS runner 20 | ENV NODE_ENV=production 21 | COPY --from=builder /app/refine/public ./public 22 | RUN mkdir .next 23 | RUN chown refine:nodejs .next 24 | COPY --from=builder --chown=refine:nodejs /app/refine/.next/standalone ./ 25 | COPY --from=builder --chown=refine:nodejs /app/refine/.next/static ./.next/static 26 | 27 | USER refine 28 | EXPOSE 3000 29 | ENV PORT=3000 30 | ENV HOSTNAME="0.0.0.0" 31 | CMD ["node", "server.js"] -------------------------------------------------------------------------------- /samples/marketing/src/frontend/README.MD: -------------------------------------------------------------------------------- 1 | ## TODO: describe the frontend app 2 | 3 | ## How I started 4 | ``` 5 | npm -i 6 | ``` 7 | 8 | ## How to run it 9 | ```shell 10 | npm run dev 11 | ``` -------------------------------------------------------------------------------- /samples/marketing/src/frontend/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | images: { 5 | domains: ['dalleproduse.blob.core.windows.net'], 6 | remotePatterns: [ 7 | { 8 | protocol: 'https', 9 | hostname: 'dalleproduse.blob.core.windows.net', 10 | port: '**', 11 | pathname: '**', 12 | }, 13 | ], 14 | }, 15 | }; 16 | 17 | export default nextConfig; -------------------------------------------------------------------------------- /samples/marketing/src/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Learning", 3 | "version": "0.1.0", 4 | "private": true, 5 | "engines": { 6 | "node": ">=18.0.0" 7 | }, 8 | "scripts": { 9 | "dev": "cross-env NODE_OPTIONS=--max_old_space_size=4096 refine dev", 10 | "build": "refine build", 11 | "start": "refine start", 12 | "lint": "eslint '**/*.{js,jsx,ts,tsx}'", 13 | "refine": "refine" 14 | }, 15 | "dependencies": { 16 | "@emotion/react": "^11.8.2", 17 | "@emotion/styled": "^11.8.1", 18 | "@fontsource/roboto": "^4.5.8", 19 | "@microsoft/signalr": "^8.0.0", 20 | "@mui/icons-material": "^5.8.3", 21 | "@mui/lab": "^5.0.0-alpha.85", 22 | "@mui/material": "^5.8.6", 23 | "@mui/x-data-grid": "^6.6.0", 24 | "@refinedev/cli": "^2.16.21", 25 | "@refinedev/core": "^4.47.1", 26 | "@refinedev/devtools": "^1.1.32", 27 | "@refinedev/kbar": "^1.3.6", 28 | "@refinedev/mui": "^5.14.4", 29 | "@refinedev/nextjs-router": "^6.0.0", 30 | "@refinedev/react-hook-form": "^4.8.14", 31 | "@refinedev/simple-rest": "^5.0.1", 32 | "js-cookie": "^3.0.5", 33 | "next": "^14.2.5", 34 | "react": "^18.0.0", 35 | "react-dom": "^18.0.0", 36 | "react-flippy": "^1.1.0", 37 | "uuidv4": "^6.2.13" 38 | }, 39 | "devDependencies": { 40 | "@types/js-cookie": "^3.0.6", 41 | "@types/node": "^18.0.0", 42 | "@types/react": "^18.0.0", 43 | "@types/react-dom": "^18.0.0", 44 | "@typescript-eslint/parser": "5.48.0", 45 | "cross-env": "^7.0.3", 46 | "eslint": "^8", 47 | "eslint-config-next": "14.1.0", 48 | "typescript": "^4.7.4" 49 | }, 50 | "refine": { 51 | "projectId": "Z0Y3hf-6BZFyJ-VWX5Qq" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/background1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/background1.webp -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/check.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/face.jpg -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/face2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/face2.jpg -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/icons/docs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/icons/docs.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/icons/edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/icons/edge.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/icons/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/icons/pdf.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/icons/xslx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/icons/xslx.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/public/static/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/public/static/x.png -------------------------------------------------------------------------------- /samples/marketing/src/frontend/src/app/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/marketing/src/frontend/src/app/icon.ico -------------------------------------------------------------------------------- /samples/marketing/src/frontend/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { DevtoolsProvider } from "@providers/devtools"; 2 | import { Refine } from "@refinedev/core"; 3 | import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar"; 4 | import { RefineSnackbarProvider, notificationProvider } from "@refinedev/mui"; 5 | import routerProvider from "@refinedev/nextjs-router"; 6 | import { Metadata } from "next"; 7 | import { cookies } from "next/headers"; 8 | import React, { Suspense } from "react"; 9 | 10 | export const metadata: Metadata = { 11 | title: "Refine", 12 | description: "Generated by create refine app", 13 | icons: { 14 | icon: "/favicon.ico", 15 | }, 16 | }; 17 | 18 | export default function RootLayout({ 19 | children, 20 | }: Readonly<{ 21 | children: React.ReactNode; 22 | }>) { 23 | 24 | return ( 25 | 26 | 27 | 28 | 29 | 30 | 31 | 47 | {children} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/src/app/not-found.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Authenticated } from "@refinedev/core"; 4 | import { ErrorComponent } from "@refinedev/mui"; 5 | import { Suspense } from "react"; 6 | 7 | export default function NotFound() { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { Suspense } from "react"; 4 | import { NavigateToResource } from "@refinedev/nextjs-router"; 5 | 6 | export default function IndexPage() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/src/providers/devtools/index.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { 4 | DevtoolsPanel, 5 | DevtoolsProvider as DevtoolsProviderBase, 6 | } from "@refinedev/devtools"; 7 | import React from "react"; 8 | 9 | export const DevtoolsProvider = (props: React.PropsWithChildren) => { 10 | return ( 11 | 12 | {props.children} 13 | 14 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /samples/marketing/src/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "plugins": [ 21 | { 22 | "name": "next" 23 | } 24 | ], 25 | "paths": { 26 | "@*": [ 27 | "./src/*" 28 | ], 29 | "@pages/*": [ 30 | "./pages/*" 31 | ] 32 | }, 33 | "incremental": true 34 | }, 35 | "include": [ 36 | "next-env.d.ts", 37 | "**/*.ts", 38 | "**/*.tsx", 39 | ".next/types/**/*.ts" 40 | ], 41 | "exclude": [ 42 | "node_modules" 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /samples/support-center/azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json 2 | name: ai-support-center 3 | metadata: 4 | template: azd-init@1.8.2 5 | hooks: 6 | postprovision: 7 | interactive: false 8 | shell: sh 9 | run: infra/azd-hooks/load-envs.sh 10 | infra: 11 | provider: bicep 12 | path: infra 13 | module: main 14 | services: 15 | backend: 16 | project: src/backend 17 | host: containerapp 18 | language: dotnet 19 | docker: 20 | path: Dockerfile 21 | context: ../../../../ 22 | frontend: 23 | project: src/frontend 24 | host: containerapp 25 | language: ts 26 | dist: build 27 | docker: 28 | path: Dockerfile 29 | 30 | -------------------------------------------------------------------------------- /samples/support-center/docs/media/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/docs/media/arch.png -------------------------------------------------------------------------------- /samples/support-center/docs/media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/docs/media/screenshot.png -------------------------------------------------------------------------------- /samples/support-center/docs/media/supportcenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/docs/media/supportcenter.png -------------------------------------------------------------------------------- /samples/support-center/infra/app/db.bicep: -------------------------------------------------------------------------------- 1 | param accountName string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param containers array = [ 6 | { 7 | name: 'customer' 8 | id: 'customer' 9 | partitionKey: '/id' 10 | } 11 | ] 12 | 13 | param databaseName string = '' 14 | param principalIds array = [] 15 | 16 | // Because databaseName is optional in main.bicep, we make sure the database name is set here. 17 | var defaultDatabaseName = 'customer-support' 18 | var actualDatabaseName = !empty(databaseName) ? databaseName : defaultDatabaseName 19 | 20 | module cosmos '../core/database/cosmos/sql/cosmos-sql-db.bicep' = { 21 | name: 'cosmos-sql' 22 | params: { 23 | accountName: accountName 24 | location: location 25 | tags: tags 26 | containers: containers 27 | databaseName: actualDatabaseName 28 | principalIds: principalIds 29 | } 30 | } 31 | 32 | output accountName string = cosmos.outputs.accountName 33 | output connectionStringKey string = cosmos.outputs.connectionStringKey 34 | output databaseName string = cosmos.outputs.databaseName 35 | output endpoint string = cosmos.outputs.endpoint 36 | output roleDefinitionId string = cosmos.outputs.roleDefinitionId 37 | -------------------------------------------------------------------------------- /samples/support-center/infra/azd-hooks/load-envs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pushd src/frontend || exit 1 4 | 5 | # Check if the variable is set 6 | if [ -z "${AZURE_BACKEND_ENDPOINT}" ]; then 7 | echo "AZURE_BACKEND_ENDPOINT is not set. Exiting." 8 | popd 9 | exit 1 10 | fi 11 | echo "AZURE_BACKEND_ENDPOINT is set to: ${AZURE_BACKEND_ENDPOINT}" 12 | echo "Replacing with ${AZURE_BACKEND_ENDPOINT}" 13 | 14 | # Use sed to replace the placeholder 15 | sed -i "s||${AZURE_BACKEND_ENDPOINT}|g" .env.azureConfig 16 | 17 | # Verify the replacement 18 | echo "Contents of .env.azureConfig after replacement:" 19 | cat .env.azureConfig 20 | 21 | popd || exit 1 -------------------------------------------------------------------------------- /samples/support-center/infra/azd-hooks/postprovision.ps1: -------------------------------------------------------------------------------- 1 | # Import the necessary modules 2 | # Import-Module Az 3 | # Import-Module Az.CosmosDB 4 | # Import-Module CosmosDB 5 | 6 | $subcriptionId = "" 7 | $resourceGroupName = "rg-oagents-support-center" 8 | $cosmosDbAccountName = "" 9 | $databaseName = "customer-support" 10 | $containerName = "items" 11 | $partitionKey = "/id" 12 | 13 | # Authenticate to Azure (if not already authenticated) 14 | Write-Host "Authenticating to Azure..." 15 | Connect-AzAccount -Identity 16 | Set-AzContext -Subscription $subcriptionId 17 | 18 | Write-Host "Resource Group: $resourceGroupName" 19 | Write-Host "Cosmos DB Account: $cosmosDbAccountName" 20 | Write-Host "Database Name: $databaseName" 21 | Write-Host "Container Name: $containerName" 22 | Write-Host "Partition Key Path: $partitionKeyPath" 23 | 24 | $cosmosDbContext = New-CosmosDbContext -Account $cosmosDbAccountName -Database $databaseName -ResourceGroup $resourceGroupName 25 | 26 | $document = @" 27 | { 28 | "id": "1234", 29 | "Name": "User", 30 | "Email": "user@test.com", 31 | "Phone": "+1123456789", 32 | "Address": "Contoso Address 123, CN." 33 | } 34 | "@ 35 | 36 | New-CosmosDbDocument -Context $cosmosDbContext -CollectionId $containerName -DocumentBody $document -PartitionKey $partitionkey -------------------------------------------------------------------------------- /samples/support-center/infra/core/database/cosmos/cosmos-account.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cosmos DB account.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' 7 | 8 | @allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) 9 | param kind string 10 | 11 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { 12 | name: name 13 | kind: kind 14 | location: location 15 | tags: tags 16 | properties: { 17 | consistencyPolicy: { defaultConsistencyLevel: 'Session' } 18 | locations: [ 19 | { 20 | locationName: location 21 | failoverPriority: 0 22 | isZoneRedundant: false 23 | } 24 | ] 25 | databaseAccountOfferType: 'Standard' 26 | enableAutomaticFailover: false 27 | enableMultipleWriteLocations: false 28 | apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.0' } : {} 29 | capabilities: [ { name: 'EnableServerless' } ] 30 | } 31 | } 32 | 33 | 34 | output connectionStringKey string = connectionStringKey 35 | output endpoint string = cosmos.properties.documentEndpoint 36 | output id string = cosmos.id 37 | output name string = cosmos.name 38 | -------------------------------------------------------------------------------- /samples/support-center/infra/core/database/cosmos/sql/cosmos-sql-account.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates an Azure Cosmos DB for NoSQL account.' 2 | param name string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | module cosmos '../../cosmos/cosmos-account.bicep' = { 7 | name: 'cosmos-account' 8 | params: { 9 | name: name 10 | location: location 11 | tags: tags 12 | kind: 'GlobalDocumentDB' 13 | } 14 | } 15 | 16 | output connectionStringKey string = cosmos.outputs.connectionStringKey 17 | output endpoint string = cosmos.outputs.endpoint 18 | output id string = cosmos.outputs.id 19 | output name string = cosmos.outputs.name 20 | -------------------------------------------------------------------------------- /samples/support-center/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a SQL role assignment under an Azure Cosmos DB account.' 2 | param accountName string 3 | 4 | param roleDefinitionId string 5 | param principalId string = '' 6 | 7 | resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { 8 | parent: cosmos 9 | name: guid(roleDefinitionId, principalId, cosmos.id) 10 | properties: { 11 | principalId: principalId 12 | roleDefinitionId: roleDefinitionId 13 | scope: cosmos.id 14 | } 15 | } 16 | 17 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { 18 | name: accountName 19 | } 20 | -------------------------------------------------------------------------------- /samples/support-center/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep: -------------------------------------------------------------------------------- 1 | metadata description = 'Creates a SQL role definition under an Azure Cosmos DB account.' 2 | param accountName string 3 | 4 | resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { 5 | parent: cosmos 6 | name: guid(cosmos.id, accountName, 'sql-role') 7 | properties: { 8 | assignableScopes: [ 9 | cosmos.id 10 | ] 11 | permissions: [ 12 | { 13 | dataActions: [ 14 | 'Microsoft.DocumentDB/databaseAccounts/readMetadata' 15 | 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' 16 | 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' 17 | ] 18 | notDataActions: [] 19 | } 20 | ] 21 | roleName: 'Reader Writer' 22 | type: 'CustomRole' 23 | } 24 | } 25 | 26 | resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { 27 | name: accountName 28 | } 29 | 30 | output id string = roleDefinition.id 31 | -------------------------------------------------------------------------------- /samples/support-center/infra/core/database/postgresql/flexibleserver.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param sku object 6 | param storage object 7 | param administratorLogin string 8 | @secure() 9 | param administratorLoginPassword string 10 | param databaseNames array = [] 11 | param allowAzureIPsFirewall bool = false 12 | param allowAllIPsFirewall bool = false 13 | param allowedSingleIPs array = [] 14 | 15 | // PostgreSQL version 16 | param version string 17 | 18 | // Latest official version 2022-12-01 does not have Bicep types available 19 | resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = { 20 | location: location 21 | tags: tags 22 | name: name 23 | sku: sku 24 | properties: { 25 | version: version 26 | administratorLogin: administratorLogin 27 | administratorLoginPassword: administratorLoginPassword 28 | storage: storage 29 | highAvailability: { 30 | mode: 'Disabled' 31 | } 32 | } 33 | 34 | resource database 'databases' = [for name in databaseNames: { 35 | name: name 36 | }] 37 | 38 | resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) { 39 | name: 'allow-all-IPs' 40 | properties: { 41 | startIpAddress: '0.0.0.0' 42 | endIpAddress: '255.255.255.255' 43 | } 44 | } 45 | 46 | resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) { 47 | name: 'allow-all-azure-internal-IPs' 48 | properties: { 49 | startIpAddress: '0.0.0.0' 50 | endIpAddress: '0.0.0.0' 51 | } 52 | } 53 | 54 | resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: { 55 | name: 'allow-single-${replace(ip, '.', '')}' 56 | properties: { 57 | startIpAddress: ip 58 | endIpAddress: ip 59 | } 60 | }] 61 | 62 | } 63 | 64 | output POSTGRES_DOMAIN_NAME string = postgresServer.properties.fullyQualifiedDomainName 65 | -------------------------------------------------------------------------------- /samples/support-center/infra/core/documentintelligence/document-intelligence.bicep: -------------------------------------------------------------------------------- 1 | @description('Location for all resources.') 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @allowed([ 6 | 'F0' 7 | 'S0' 8 | ]) 9 | 10 | param sku string = 'S0' 11 | 12 | 13 | param documentIntelligenceName string = '' 14 | // Because name is optional in main.bicep, we make sure the name is set here. 15 | var defaultName = 'doc-intelligence-${uniqueString(resourceGroup().id)}' 16 | var actualname = !empty(documentIntelligenceName) ? documentIntelligenceName : defaultName 17 | 18 | resource cognitiveService 'Microsoft.CognitiveServices/accounts@2021-10-01' = { 19 | name: actualname 20 | location: 'westeurope' //invoice model is only available in eastus, west us2 and west europe for now 21 | tags: tags 22 | sku: { 23 | name: sku 24 | } 25 | kind: 'FormRecognizer' 26 | identity: { 27 | type: 'SystemAssigned' 28 | } 29 | properties: { 30 | customSubDomainName: actualname 31 | networkAcls: { 32 | defaultAction: 'Allow' 33 | virtualNetworkRules: [] 34 | ipRules: [] 35 | } 36 | publicNetworkAccess: 'Enabled' 37 | } 38 | } 39 | 40 | output id string = cognitiveService.id 41 | output endpoint string = 'https://${actualname}.cognitiveservices.azure.com/' 42 | output name string = cognitiveService.name 43 | //output key string = cognitiveService.listKeys().key1 44 | -------------------------------------------------------------------------------- /samples/support-center/infra/modules/fetch-container-image.bicep: -------------------------------------------------------------------------------- 1 | param exists bool 2 | param name string 3 | 4 | resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { 5 | name: name 6 | } 7 | 8 | output containers array = exists ? existingApp.properties.template.containers : [] 9 | -------------------------------------------------------------------------------- /samples/support-center/infra/shared/apps-env.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param logAnalyticsWorkspaceName string 6 | param applicationInsightsName string = '' 7 | 8 | resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-10-01' = { 9 | name: name 10 | location: location 11 | tags: tags 12 | properties: { 13 | appLogsConfiguration: { 14 | destination: 'log-analytics' 15 | logAnalyticsConfiguration: { 16 | customerId: logAnalyticsWorkspace.properties.customerId 17 | sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey 18 | } 19 | } 20 | daprAIConnectionString: applicationInsights.properties.ConnectionString 21 | } 22 | } 23 | 24 | resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { 25 | name: logAnalyticsWorkspaceName 26 | } 27 | 28 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { 29 | name: applicationInsightsName 30 | } 31 | 32 | output name string = containerAppsEnvironment.name 33 | output domain string = containerAppsEnvironment.properties.defaultDomain 34 | -------------------------------------------------------------------------------- /samples/support-center/infra/shared/keyvault.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | @description('Service principal that should be granted read access to the KeyVault. If unset, no service principal is granted access by default') 6 | param principalId string = '' 7 | 8 | var defaultAccessPolicies = !empty(principalId) ? [ 9 | { 10 | objectId: principalId 11 | permissions: { secrets: [ 'get', 'list' ] } 12 | tenantId: subscription().tenantId 13 | } 14 | ] : [] 15 | 16 | resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { 17 | name: name 18 | location: location 19 | tags: tags 20 | properties: { 21 | tenantId: subscription().tenantId 22 | sku: { family: 'A', name: 'standard' } 23 | enabledForTemplateDeployment: true 24 | accessPolicies: union(defaultAccessPolicies, [ 25 | // define access policies here 26 | ]) 27 | } 28 | } 29 | 30 | output endpoint string = keyVault.properties.vaultUri 31 | output name string = keyVault.name 32 | -------------------------------------------------------------------------------- /samples/support-center/infra/shared/monitoring.bicep: -------------------------------------------------------------------------------- 1 | param logAnalyticsName string 2 | param applicationInsightsName string 3 | param location string = resourceGroup().location 4 | param tags object = {} 5 | 6 | resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { 7 | name: logAnalyticsName 8 | location: location 9 | tags: tags 10 | properties: any({ 11 | retentionInDays: 30 12 | features: { 13 | searchVersion: 1 14 | } 15 | sku: { 16 | name: 'PerGB2018' 17 | } 18 | }) 19 | } 20 | 21 | resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { 22 | name: applicationInsightsName 23 | location: location 24 | tags: tags 25 | kind: 'web' 26 | properties: { 27 | Application_Type: 'web' 28 | WorkspaceResourceId: logAnalytics.id 29 | } 30 | } 31 | 32 | output applicationInsightsName string = applicationInsights.name 33 | output logAnalyticsWorkspaceId string = logAnalytics.id 34 | output logAnalyticsWorkspaceName string = logAnalytics.name 35 | -------------------------------------------------------------------------------- /samples/support-center/infra/shared/registry.bicep: -------------------------------------------------------------------------------- 1 | param name string 2 | param location string = resourceGroup().location 3 | param tags object = {} 4 | 5 | param adminUserEnabled bool = true 6 | param anonymousPullEnabled bool = false 7 | param dataEndpointEnabled bool = false 8 | param encryption object = { 9 | status: 'disabled' 10 | } 11 | param networkRuleBypassOptions string = 'AzureServices' 12 | param publicNetworkAccess string = 'Enabled' 13 | param sku object = { 14 | name: 'Standard' 15 | } 16 | param zoneRedundancy string = 'Disabled' 17 | 18 | // 2023-01-01-preview needed for anonymousPullEnabled 19 | resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = { 20 | name: name 21 | location: location 22 | tags: tags 23 | sku: sku 24 | properties: { 25 | adminUserEnabled: adminUserEnabled 26 | anonymousPullEnabled: anonymousPullEnabled 27 | dataEndpointEnabled: dataEndpointEnabled 28 | encryption: encryption 29 | networkRuleBypassOptions: networkRuleBypassOptions 30 | publicNetworkAccess: publicNetworkAccess 31 | zoneRedundancy: zoneRedundancy 32 | } 33 | } 34 | 35 | output loginServer string = containerRegistry.properties.loginServer 36 | output name string = containerRegistry.name 37 | -------------------------------------------------------------------------------- /samples/support-center/seed-invoice-memory/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base 2 | WORKDIR /app 3 | 4 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 5 | WORKDIR /src 6 | COPY ["seed-invoice-memory/seed-invoice-memory.csproj", "seed-invoice-memory/"] 7 | RUN dotnet restore "seed-invoice-memory/seed-invoice-memory.csproj" 8 | COPY . . 9 | WORKDIR "/seed-invoice-memory/" 10 | RUN dotnet build "seed-invoice-memory.csproj" -c Release -o /app/build 11 | 12 | FROM build AS publish 13 | RUN dotnet publish "seed-invoice-memory.csproj" -c Release -o /app/publish /p:UseAppHost=false 14 | 15 | FROM base AS final 16 | WORKDIR /app 17 | COPY --from=publish /app/publish . 18 | ENTRYPOINT ["dotnet", "seed-invoice-memory.dll"] 19 | -------------------------------------------------------------------------------- /samples/support-center/seed-invoice-memory/README.md: -------------------------------------------------------------------------------- 1 | # TODO -------------------------------------------------------------------------------- /samples/support-center/seed-invoice-memory/config/appsettings.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "embeddingDeploymentOrModelId": "text-embedding-ada-002", 3 | "endpoint": " https://.openai.azure.com/", 4 | "apiKey": "", 5 | "searchEndpoint": "https://.search.windows.net", 6 | "searchKey": "", 7 | "searchIndex": "invoice", 8 | "documentIntelligenceEndpoint": "https://.cognitiveservices.azure.com/", 9 | "documentIntelligenceKey": "" 10 | } -------------------------------------------------------------------------------- /samples/support-center/seed-invoice-memory/seed-invoice-memory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | semantic-kernel-rag-chat 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/support-center/seed-memory/Benefit_Options.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/Benefit_Options.pdf -------------------------------------------------------------------------------- /samples/support-center/seed-memory/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base 2 | WORKDIR /app 3 | 4 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build 5 | WORKDIR /src 6 | COPY ["util/seed-memory/seed-memory.csproj", "util/seed-memory/"] 7 | RUN dotnet restore "util/seed-memory/seed-memory.csproj" 8 | COPY . . 9 | WORKDIR "/src/util/seed-memory" 10 | RUN dotnet build "seed-memory.csproj" -c Release -o /app/build 11 | 12 | FROM build AS publish 13 | RUN dotnet publish "seed-memory.csproj" -c Release -o /app/publish /p:UseAppHost=false 14 | 15 | FROM base AS final 16 | WORKDIR /app 17 | COPY --from=publish /app/publish . 18 | ENTRYPOINT ["dotnet", "seed-memory.dll"] 19 | -------------------------------------------------------------------------------- /samples/support-center/seed-memory/Northwind_Health_Plus_Benefits_Details.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/Northwind_Health_Plus_Benefits_Details.pdf -------------------------------------------------------------------------------- /samples/support-center/seed-memory/Northwind_Standard_Benefits_Details.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/Northwind_Standard_Benefits_Details.pdf -------------------------------------------------------------------------------- /samples/support-center/seed-memory/PerksPlus.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/PerksPlus.pdf -------------------------------------------------------------------------------- /samples/support-center/seed-memory/README.md: -------------------------------------------------------------------------------- 1 | # TODO -------------------------------------------------------------------------------- /samples/support-center/seed-memory/config/appsettings.template.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceType": "AzureOpenAI", 3 | "serviceId": "gpt-4-32k", 4 | "deploymentOrModelId": "gpt-4-32k", 5 | "embeddingDeploymentOrModelId": "text-embedding-ada-002", 6 | "endpoint": " https://.openai.azure.com/", 7 | "apiKey": "", 8 | "qdrantEndpoint": "" 9 | } -------------------------------------------------------------------------------- /samples/support-center/seed-memory/employee_handbook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/employee_handbook.pdf -------------------------------------------------------------------------------- /samples/support-center/seed-memory/role_library.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/project-oagents/6966d92eae2660b27419c13c2675196bde367365/samples/support-center/seed-memory/role_library.pdf -------------------------------------------------------------------------------- /samples/support-center/src/backend/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md 26 | !**/.gitignore 27 | !.git/HEAD 28 | !.git/config 29 | !.git/packed-refs 30 | !.git/refs/heads/** -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Conversation/ConversationPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class ConversationPrompts 4 | { 5 | public static string Answer = """ 6 | You are a helpful customer support/service agent at Contoso Electronics. Be polite, friendly and professional and answer briefly. 7 | Answer with a plain string ONLY, without any extra words or characters like '. 8 | Input: {{$input}} 9 | """; 10 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Conversation/ConversationState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class ConversationState 4 | { 5 | } 6 | 7 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/CustomerInfo/CustomerInfoPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class CustomerInfoPrompts 4 | { 5 | public static string GetCustomerInfo = """ 6 | You are a Customer Info agent, working with the Support Center. 7 | You can help customers working with their own information. 8 | Read the customer's message carefully, and then decide the appropriate plan to create. 9 | A history of the conversation is available to help you building a correct plan. 10 | 11 | If you don't know how to proceed, don't guess; instead ask for more information and use it as a final answer. 12 | If you think that the message is not clear, you can ask the customer for more information. 13 | 14 | Here is the user message: 15 | userId: {{$userId}} 16 | userMessage: {{$userMessage}} 17 | 18 | Here is the history of all messages (including the last one): 19 | {{$history}} 20 | """; 21 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/CustomerInfo/CustomerInfoState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class CustomerInfoState 4 | { 5 | [Id(0)] 6 | public CustomerInfoInternal? Info { get; set; } 7 | } 8 | 9 | public class CustomerInfoInternal 10 | { 11 | public string? Name { get; set; } 12 | public string? Email { get; set; } 13 | public string? Phone { get; set; } 14 | public string? Address { get; set; } 15 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Discount/Discount.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | using Microsoft.AI.Agents.Orleans; 3 | using Microsoft.SemanticKernel; 4 | using Microsoft.SemanticKernel.Memory; 5 | using Orleans.Runtime; 6 | using SupportCenter.Events; 7 | using SupportCenter.Options; 8 | 9 | namespace SupportCenter.Agents; 10 | 11 | [ImplicitStreamSubscription(Consts.OrleansNamespace)] 12 | public class Discount : AiAgent 13 | { 14 | private readonly ILogger _logger; 15 | 16 | protected override string Namespace => Consts.OrleansNamespace; 17 | 18 | public Discount([PersistentState("state", "messages")] IPersistentState> state, 19 | ILogger logger, 20 | [FromKeyedServices("DiscountKernel")] Kernel kernel, 21 | [FromKeyedServices("DiscountMemory")] ISemanticTextMemory memory) 22 | : base(state, memory, kernel) 23 | { 24 | _logger = logger ?? throw new ArgumentNullException(nameof(logger)); 25 | } 26 | 27 | public async override Task HandleEvent(Event item) 28 | { 29 | switch (item.Type) 30 | { 31 | case nameof(EventType.UserConnected): 32 | // The user reconnected, let's send the last message if we have one 33 | string? lastMessage = _state.State.History.LastOrDefault()?.Message; 34 | if (lastMessage == null) 35 | { 36 | return; 37 | } 38 | break; 39 | default: 40 | break; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Discount/DiscountState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class DiscountState 4 | { 5 | } 6 | 7 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Dispatcher/DispatcherPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class DispatcherPrompts 4 | { 5 | public static string GetIntent = """ 6 | You are a dispatcher agent, working with the Support Center. 7 | You can help customers with their issues, and you can also assign tickets to other AI agents. 8 | Read the customer's message carefully, and then decide the appropriate intent. 9 | A history of the conversation is available to help you make a decision. 10 | 11 | If you don't know the intent, don't guess; instead respond with "Unknown". 12 | There may be multiple intents, but you should choose the most appropriate one. 13 | If you think that the message is not clear, you can ask the customer for more information. 14 | 15 | You can choose between the following intents: 16 | {{$choices}} 17 | 18 | Here are few examples: 19 | - User Input: Can you help me in updating my address? 20 | - CustomerInfo 21 | 22 | - User Input: Could you check whether my invoice has been correctly payed? 23 | - Invoice 24 | 25 | Here is the user input: 26 | User Input: {{$input}} 27 | 28 | Return the intent as a string. 29 | """; 30 | } 31 | 32 | public class Choice(string name, string description) 33 | { 34 | public string Name { get; set; } = name; 35 | public string Description { get; set; } = description; 36 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Dispatcher/DispatcherState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class DispatcherState 4 | { 5 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Invoice/InvoicePrompts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class InvoicePrompts 4 | { 5 | public static string InvoiceRequest = """ 6 | You are a helpful customer support/service agent that answers questions about user invoices based on your knowledge. 7 | Make sure that the invoice belongs to the specific user before providing the information. If needed, ask for the invoice id etc. 8 | Be polite and professional and answer briefly based on your knowledge ONLY. 9 | Invoice Id: {{$invoiceId}} 10 | Input: {{$input}} 11 | {{$invoices}} 12 | """; 13 | 14 | public static string ExtractInvoiceId = """ 15 | Instructions: Extract the invoice-id from the user message 16 | You are expert in invoices and your goal is to extract the invoice-id from the user message. 17 | Answer with the invoice id found as a plain string ONLY, without any extra characters like '. 18 | If you can't find the invoice id, don't guess; instead answer with "Unknown". 19 | 20 | What is the total amount of my latest invoice? 21 | Unknown 22 | 23 | When is my invoice INV-100 due to payment? 24 | INV-100 25 | 26 | {{$input}} 27 | 28 | """; 29 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/Invoice/InvoiceState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class InvoiceState 4 | { 5 | [Id(0)] 6 | public string? InvoiceId { get; set; } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/QnA/QnAPrompts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class QnAPrompts 4 | { 5 | public static string Answer = """ 6 | You are a helpful customer support/service agent at Contoso Electronics. Be polite and professional and answer briefly based on your knowledge ONLY. 7 | Input: {{$input}} 8 | {{$vfcon106047}} 9 | """; 10 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Agents/QnA/QnAState.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Agents; 2 | 3 | public class QnAState 4 | { 5 | } 6 | 7 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/AgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.AgentsConfigurationFactory 2 | { 3 | public static class AgentConfiguration 4 | { 5 | public static IAgentConfiguration GetAgentConfiguration(string agent) 6 | { 7 | return agent switch 8 | { 9 | "Invoice" => new InvoiceAgentConfiguration(), 10 | "Conversation" => new ConversationAgentConfiguration(), 11 | "CustomerInfo" => new CustomerInfoAgentConfiguration(), 12 | "QnA" => new QnAAgentConfiguration(), 13 | "Dispatcher" => new DispatcherAgentConfiguration(), 14 | "Discount" => new DiscountAgentConfiguration(), 15 | "SignalR" => new SignalRAgentConfiguration(), 16 | _ => throw new ArgumentException("Unsupported agent type", nameof(agent)), 17 | }; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/ConversationAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | public class ConversationAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | options.ChatDeploymentOrModelId = options.ConversationDeploymentOrModelId ?? options.ChatDeploymentOrModelId; 11 | } 12 | 13 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 14 | { 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/CustomerInfoAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | using SupportCenter.SemanticKernel.Plugins.CustomerPlugin; 4 | 5 | namespace SupportCenter.AgentsConfigurationFactory 6 | { 7 | public class CustomerInfoAgentConfiguration : IAgentConfiguration 8 | { 9 | private readonly string customerPlugin = "CustomerPlugin"; 10 | 11 | public void ConfigureOpenAI(OpenAIOptions options) 12 | { 13 | options.ChatDeploymentOrModelId = options.ConversationDeploymentOrModelId ?? options.ChatDeploymentOrModelId; 14 | } 15 | 16 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 17 | { 18 | if (kernel.Plugins.TryGetPlugin(customerPlugin, out _) == false) 19 | kernel.ImportPluginFromObject(serviceProvider.GetRequiredService(), customerPlugin); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/DiscountAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | internal class DiscountAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | } 11 | 12 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/DispatcherAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | internal class DispatcherAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | } 11 | 12 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/IAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | public interface IAgentConfiguration 7 | { 8 | void ConfigureOpenAI(OpenAIOptions options); 9 | void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/InvoiceAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | public class InvoiceAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | options.ChatDeploymentOrModelId = options.InvoiceDeploymentOrModelId ?? options.ChatDeploymentOrModelId; 11 | } 12 | 13 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 14 | { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/QnAAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | internal class QnAAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | } 11 | 12 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/AgentsConfigurationFactory/SignalRAgentConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel; 2 | using SupportCenter.Options; 3 | 4 | namespace SupportCenter.AgentsConfigurationFactory 5 | { 6 | internal class SignalRAgentConfiguration : IAgentConfiguration 7 | { 8 | public void ConfigureOpenAI(OpenAIOptions options) 9 | { 10 | } 11 | 12 | public void ConfigureKernel(Kernel kernel, IServiceProvider serviceProvider) 13 | { 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Attributes/Choice.cs: -------------------------------------------------------------------------------- 1 | using SupportCenter.Events; 2 | 3 | namespace SupportCenter.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] 6 | public class DispatcherChoice(string name, string description, EventType dispatchToEvent) : Attribute 7 | { 8 | public string Name { get; set; } = name; 9 | public string Description { get; set; } = description; 10 | public EventType DispatchToEvent { get; set; } = dispatchToEvent; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Controllers/Interactions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Orleans.Runtime; 4 | using SupportCenter.Events; 5 | using SupportCenter.Options; 6 | 7 | namespace SupportCenter.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | [ApiController] 11 | public class Interactions : ControllerBase 12 | { 13 | private readonly IClusterClient _client; 14 | 15 | public Interactions(IClusterClient client) 16 | { 17 | _client = client; 18 | } 19 | 20 | // POST api//5 21 | [HttpPost("{userId}")] 22 | public async Task Post(string userId, [FromBody] string userMessage) 23 | { 24 | var streamProvider = _client.GetStreamProvider("StreamProvider"); 25 | var streamId = StreamId.Create(Consts.OrleansNamespace, userId); // to change 26 | var stream = streamProvider.GetStream(streamId); 27 | 28 | var data = new Dictionary 29 | { 30 | { nameof(userId), userId.ToString() }, 31 | { nameof(userMessage), userMessage }, 32 | }; 33 | 34 | await stream.OnNextAsync(new Event 35 | { 36 | Type = nameof(EventType.UserChatInput), 37 | Data = data 38 | }); 39 | 40 | return $"Task {userId} accepted"; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Data/CosmosDb/Entities/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace SupportCenter.Data.CosmosDb.Entities 4 | { 5 | public class Customer : Entity 6 | { 7 | [JsonPropertyName(nameof(Name))] 8 | public string? Name { get; set; } 9 | 10 | [JsonPropertyName(nameof(Email))] 11 | public string? Email { get; set; } 12 | 13 | [JsonPropertyName(nameof(Phone))] 14 | public string? Phone { get; set; } 15 | 16 | [JsonPropertyName(nameof(Address))] 17 | public string? Address { get; set; } 18 | 19 | public override string GetPartitionKeyValue() => Id; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Data/CosmosDb/ICustomerRepository.cs: -------------------------------------------------------------------------------- 1 | using SupportCenter.Data.CosmosDb.Entities; 2 | 3 | namespace SupportCenter.Data.CosmosDb 4 | { 5 | public interface ICustomerRepository 6 | { 7 | Task GetCustomerByIdAsync(string customerId); 8 | Task> GetCustomersAsync(); 9 | Task InsertCustomerAsync(Customer customer); 10 | Task UpdateCustomerAsync(Customer customer); 11 | } 12 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Data/Entities/Entity.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace SupportCenter.Data.CosmosDb.Entities 4 | { 5 | public abstract class Entity 6 | { 7 | [JsonProperty("id")] 8 | public string Id { get; set; } = Guid.NewGuid().ToString(); 9 | 10 | [JsonProperty("_etag")] 11 | public string? ETag { get; } 12 | 13 | public DateTimeOffset LastUpdatedTime { get; set; } 14 | 15 | public abstract string GetPartitionKeyValue(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 2 | WORKDIR /app 3 | EXPOSE 5244 4 | EXPOSE 11111 5 | EXPOSE 30000 6 | 7 | ENV ASPNETCORE_URLS=http://+:5244 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG configuration=Release 11 | COPY . . 12 | RUN dotnet restore "samples/support-center/src/backend/SupportCenter.csproj" 13 | WORKDIR "/samples/support-center/src/backend" 14 | RUN dotnet build "SupportCenter.csproj" -c $configuration -o /app/build 15 | 16 | FROM build AS publish 17 | ARG configuration=Release 18 | RUN dotnet publish "SupportCenter.csproj" -c $configuration -o /app/publish 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | ENTRYPOINT ["dotnet", "SupportCenter.dll"] -------------------------------------------------------------------------------- /samples/support-center/src/backend/Events/EventTypes.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Events; 2 | 3 | public enum EventType 4 | { 5 | UserChatInput, 6 | UserConnected, 7 | UserNewConversation, 8 | AgentNotification, 9 | Unknown, 10 | 11 | // Domain specific events 12 | CustomerInfoRequested, 13 | CustomerInfoRetrieved, 14 | QnARequested, 15 | QnARetrieved, 16 | DiscountRequested, 17 | DiscountRetrieved, 18 | InvoiceRequested, 19 | InvoiceRetrieved, 20 | ConversationRequested, 21 | ConversationRetrieved, 22 | 23 | // Notification events 24 | DispatcherNotification, 25 | CustomerInfoNotification, 26 | QnANotification, 27 | DiscountNotification, 28 | InvoiceNotification 29 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Extensions/DictionaryExtension.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Extensions 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | public static class DictionaryExtensions 7 | { 8 | public static T GetValueOrDefault(this IDictionary dictionary, string key) 9 | { 10 | ArgumentNullException.ThrowIfNull(dictionary); 11 | ArgumentNullException.ThrowIfNull(key); 12 | 13 | if (dictionary.TryGetValue(key, out var value)) 14 | { 15 | if (value is T typedValue) 16 | return typedValue; 17 | 18 | try 19 | { 20 | return (T)Convert.ChangeType(value, typeof(T)); 21 | } 22 | catch (InvalidCastException) 23 | { 24 | throw new InvalidOperationException($"Value for key '{key}' is not of type {typeof(T).Name}"); 25 | } 26 | } 27 | else 28 | { 29 | return default; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Extensions/ObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Text; 3 | 4 | namespace SupportCenter.Extensions 5 | { 6 | public static class ObjectExtensions 7 | { 8 | public static string ToStringCustom(this object obj, int indentLevel = 0) 9 | { 10 | if (obj == null) 11 | { 12 | return "null"; 13 | } 14 | 15 | var type = obj.GetType(); 16 | var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); 17 | 18 | var sb = new StringBuilder(); 19 | var indent = new string(' ', indentLevel * 2); 20 | sb.AppendLine($"{indent}{type.Name} {{"); 21 | 22 | foreach (var property in properties) 23 | { 24 | var value = property.GetValue(obj, null); 25 | if (value != null && !IsSimpleType(value.GetType())) 26 | { 27 | sb.AppendLine($"{indent}{property.Name}:"); 28 | sb.Append(value.ToStringCustom(indentLevel + 1)); 29 | } 30 | else 31 | { 32 | sb.AppendLine($"{indent}{property.Name}: {value}"); 33 | } 34 | } 35 | 36 | sb.AppendLine($"{indent}}}"); 37 | return sb.ToString(); 38 | } 39 | 40 | private static bool IsSimpleType(Type type) 41 | { 42 | return type.IsPrimitive || type.IsEnum || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(DateTimeOffset) || type == typeof(TimeSpan) || type == typeof(Guid); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Extensions/SupportCenterAgentExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | using SupportCenter.SignalRHub; 3 | 4 | namespace SupportCenter.Extensions 5 | { 6 | public static class SupportCenterAgentExtensions 7 | { 8 | public static SupportCenterData GetAgentData(this Event item) 9 | { 10 | string? userId = item.Data.GetValueOrDefault("userId"); 11 | string? userMessage = item.Data.GetValueOrDefault("message") 12 | ?? item.Data.GetValueOrDefault("userMessage"); 13 | 14 | string? conversationId = SignalRConnectionsDB.GetConversationId(userId) ?? item.Data.GetValueOrDefault("id"); 15 | string id = $"{userId}/{conversationId}"; 16 | 17 | return new SupportCenterData(id, userId, userMessage); 18 | } 19 | } 20 | 21 | public record SupportCenterData(string? Id, string? UserId, string? UserMessage); 22 | } 23 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Extensions/ValidationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Core 4 | { 5 | /* 6 | * This class is used to extend the validation functionality of the application. 7 | */ 8 | public static class ValidationExtensions 9 | { 10 | /* This method is used to validate the required properties of an object. 11 | * @param obj The object to validate. 12 | * Returns: void. 13 | * Throws: ValidationException if the object is not valid. 14 | */ 15 | public static void ValidateRequiredProperties(this object obj) 16 | { 17 | var context = new ValidationContext(obj); 18 | Validator.ValidateObject(obj, context, validateAllProperties: true); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/AiSearchOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Options; 4 | 5 | public class AISearchOptions 6 | { 7 | // AI Search 8 | [Required] 9 | public string SearchEndpoint { get; set; } 10 | [Required] 11 | public string SearchKey { get; set; } 12 | [Required] 13 | public string SearchIndex { get; set; } 14 | // Embeddings 15 | [Required] 16 | public string SearchEmbeddingDeploymentOrModelId { get; set; } 17 | [Required] 18 | public string SearchEmbeddingEndpoint { get; set; } 19 | [Required] 20 | public string SearchEmbeddingApiKey { get; set; } 21 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/Consts.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.Options; 2 | 3 | public static class Consts 4 | { 5 | public const string OrleansNamespace = "SupportCenter"; 6 | } 7 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/CosmosDbContainerOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Options 4 | { 5 | public class CosmosDbContainerOptions 6 | { 7 | [Required] 8 | public string? DatabaseName { get; set; } 9 | 10 | [Required] 11 | public string? ContainerName { get; set; } 12 | 13 | [Required] 14 | public string? PartitionKey { get; set; } 15 | 16 | [Required] 17 | public string? EntityName { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/CosmosDbOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Options 4 | { 5 | public class CosmosDbOptions 6 | { 7 | public string? AccountUri { get; set; } 8 | 9 | public string? AccountKey { get; set; } 10 | 11 | public IEnumerable? Containers { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/OpenAIOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Options; 4 | 5 | public class OpenAIOptions 6 | { 7 | // Embeddings 8 | [Required] 9 | public string EmbeddingsEndpoint { get; set; } = string.Empty; 10 | [Required] 11 | public string EmbeddingsApiKey { get; set; } = string.Empty; 12 | [Required] 13 | public string EmbeddingsDeploymentOrModelId { get; set; } = string.Empty; 14 | 15 | // Chat 16 | [Required] 17 | public string ChatEndpoint { get; set; } = string.Empty; 18 | [Required] 19 | public string ChatApiKey { get; set; } = string.Empty; 20 | [Required] 21 | public string ChatDeploymentOrModelId { get; set; } = string.Empty; 22 | 23 | public string? InvoiceDeploymentOrModelId { get; set; } 24 | public string? ConversationDeploymentOrModelId { get; set; } 25 | 26 | // TextToImage 27 | /*[Required] 28 | public string? ImageEndpoint { get; set; } 29 | [Required] 30 | public string? ImageApiKey { get; set; } 31 | // When using OpenAI, this is not required. 32 | public string? ImageDeploymentOrModelId { get; set; }*/ 33 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Options/QdrantOptions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | 3 | namespace SupportCenter.Options; 4 | public class QdrantOptions 5 | { 6 | [Required] 7 | public string Endpoint { get; set; } = string.Empty; 8 | [Required] 9 | public int VectorSize { get; set; } 10 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "https": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "https://localhost:7100;http://localhost:5129" 12 | }, 13 | "http": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "http://localhost:5129" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Container (Dockerfile)": { 32 | "commandName": "Docker", 33 | "launchBrowser": true, 34 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 35 | "environmentVariables": { 36 | "ASPNETCORE_HTTPS_PORTS": "8081", 37 | "ASPNETCORE_HTTP_PORTS": "8080" 38 | }, 39 | "publishAllPorts": true, 40 | "useSSL": true 41 | } 42 | }, 43 | "$schema": "http://json.schemastore.org/launchsettings.json", 44 | "iisSettings": { 45 | "windowsAuthentication": false, 46 | "anonymousAuthentication": true, 47 | "iisExpress": { 48 | "applicationUrl": "http://localhost:3992", 49 | "sslPort": 44350 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/AgentTypes.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.SignalRHub; 2 | 3 | public enum AgentType 4 | { 5 | Chat, 6 | Dispatcher, 7 | QnA, 8 | CustomerInfo, 9 | Discount, 10 | Invoice, 11 | Notification, 12 | Conversation, 13 | Unknown 14 | } 15 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/FrontEndMessage.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.SignalRHub; 2 | 3 | public class ChatMessage 4 | { 5 | public string? Id { get; set; } 6 | public string? ConversationId { get; set; } 7 | public string? UserId { get; set; } 8 | public string? Text { get; set; } 9 | public string? Sender { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/ISignalRService.cs: -------------------------------------------------------------------------------- 1 | namespace SupportCenter.SignalRHub; 2 | public interface ISignalRService 3 | { 4 | Task SendMessageToClient(string messageId, string userId, string message, AgentType senderType); 5 | } 6 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/ISupportCenterHub.cs: -------------------------------------------------------------------------------- 1 | using SupportCenter.SignalRHub; 2 | 3 | namespace SupportCenter.SignalRHub; 4 | 5 | public interface ISupportCenterHub 6 | { 7 | public Task ConnectToAgent(string userId); 8 | 9 | public Task ChatMessage(ChatMessage frontEndMessage, IClusterClient clusterClient); 10 | 11 | public Task SendMessageToSpecificClient(string userId, string message); 12 | } 13 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/SignalRConnectionsDB.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace SupportCenter.SignalRHub; 4 | public static class SignalRConnectionsDB 5 | { 6 | public static ConcurrentDictionary ConnectionByUser { get; } = new ConcurrentDictionary(); 7 | 8 | // Get conversationId by userId 9 | public static string? GetConversationId(string userId) 10 | { 11 | if (string.IsNullOrWhiteSpace(userId)) 12 | { 13 | return null; 14 | } 15 | 16 | if (ConnectionByUser.TryGetValue(userId, out var connection)) 17 | { 18 | return connection.ConversationId; 19 | } 20 | return null; 21 | } 22 | } 23 | 24 | public class Connection(string connectionId, string conversationId) 25 | { 26 | public string? Id { get; set; } = connectionId; 27 | public string? ConversationId { get; set; } = conversationId; 28 | 29 | public override bool Equals(object? obj) 30 | { 31 | if (obj == null || GetType() != obj.GetType()) 32 | { 33 | return false; 34 | } 35 | var other = (Connection)obj; 36 | return Id == other.Id && ConversationId == other.ConversationId; 37 | } 38 | 39 | public override int GetHashCode() 40 | { 41 | return HashCode.Combine(Id, ConversationId); 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /samples/support-center/src/backend/SignalRHub/SignalRService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | 3 | namespace SupportCenter.SignalRHub; 4 | 5 | public class SignalRService(IHubContext hubContext) : ISignalRService 6 | { 7 | public async Task SendMessageToClient(string messageId, string userId, string message, AgentType senderType) 8 | { 9 | var connection = SignalRConnectionsDB.ConnectionByUser[userId]; 10 | if (connection == null || connection.Id == null) 11 | { 12 | return; 13 | } 14 | 15 | var chatMessage = new ChatMessage() 16 | { 17 | Id = messageId, 18 | ConversationId = connection.ConversationId, 19 | UserId = userId, 20 | Text = message, 21 | Sender = senderType.ToString() 22 | }; 23 | await hubContext.Clients.Client(connection.Id).SendAsync("ReceiveMessage", chatMessage); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/appsettings.local.template.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/support-center/src/backend/appsettings.local.template.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft.AspNetCore": "Information", 7 | "Microsoft.AspNetCore.SignalR": "Debug", 8 | "Microsoft.AspNetCore.Http.Connections": "Debug" 9 | } 10 | }, 11 | 12 | "ApplicationInsights": { 13 | "ConnectionString": "InstrumentationKey=;IngestionEndpoint=https://.applicationinsights.azure.com/" 14 | }, 15 | 16 | "AllowedHosts": "*", 17 | 18 | "OpenAIOptions": { 19 | "ChatDeploymentOrModelId": "", 20 | "InvoiceDeploymentOrModelId": "", 21 | "ConversationDeploymentOrModelId": "", 22 | "ChatEndpoint": "https://.openai.azure.com/", 23 | "ChatApiKey": "", 24 | "EmbeddingsDeploymentOrModelId": "text-embedding-ada-002", 25 | "EmbeddingsEndpoint": "https://.openai.azure.com/", 26 | "EmbeddingsApiKey": "" 27 | }, 28 | 29 | "CosmosDbOptions": { 30 | "AccountUri": "", 31 | "AccountKey": "", 32 | "Containers": [ 33 | { 34 | "DatabaseName": "customer-support", 35 | "ContainerName": "customer", 36 | "PartitionKey": "/id", 37 | "EntityName": "Customer" 38 | } 39 | ] 40 | }, 41 | 42 | "QdrantOptions": { 43 | "Endpoint": "http://qdrant:6333", 44 | "VectorSize": "1536" 45 | }, 46 | 47 | "AISearchOptions": { 48 | "SearchEndpoint": "https://.search.windows.net", 49 | "SearchKey": "", 50 | "SearchIndex": "invoices", 51 | "SearchEmbeddingDeploymentOrModelId": "text-embedding-ada-002", 52 | "SearchEmbeddingEndpoint": "https://.openai.azure.com/", 53 | "SearchEmbeddingApiKey": "" 54 | } 55 | } -------------------------------------------------------------------------------- /samples/support-center/src/frontend/.env.azureConfig: -------------------------------------------------------------------------------- 1 | # ENV used to build and deploy the app on Azure 2 | # ATTENTION: DO NOT STORE SECRETS HERE 3 | VITE_OAGENT_CLIENT_ID=support-center-clientid 4 | VITE_OAGENT_BASE_URL= -------------------------------------------------------------------------------- /samples/support-center/src/frontend/.env.localConfig: -------------------------------------------------------------------------------- 1 | # ENV used to run the app locally by using the backend running locally 2 | # ATTENTION: DO NOT STORE SECRETS HERE 3 | 4 | VITE_OAGENT_CLIENT_ID=support-center-clientid 5 | VITE_OAGENT_BASE_URL=https://localhost:7100/ 6 | VITE_IS_MOCK_ENABLED=false -------------------------------------------------------------------------------- /samples/support-center/src/frontend/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:react-hooks/recommended', 8 | ], 9 | ignorePatterns: ['dist', '.eslintrc.cjs'], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['react-refresh'], 12 | rules: { 13 | 'react-refresh/only-export-components': [ 14 | 'warn', 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json package-lock.json* .npmrc* ./ 6 | 7 | RUN npm install 8 | 9 | RUN npm i -g serve 10 | 11 | COPY . . 12 | 13 | RUN npm run azure 14 | 15 | EXPOSE 3000 16 | 17 | CMD [ "serve", "-s", "dist" ] -------------------------------------------------------------------------------- /samples/support-center/src/frontend/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default { 18 | // other rules... 19 | parserOptions: { 20 | ecmaVersion: 'latest', 21 | sourceType: 'module', 22 | project: ['./tsconfig.json', './tsconfig.node.json'], 23 | tsconfigRootDir: __dirname, 24 | }, 25 | } 26 | ``` 27 | 28 | - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` 29 | - Optionally add `plugin:@typescript-eslint/stylistic-type-checked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list 31 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Support Center 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "support-center-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "azure": "vite build --mode azureConfig", 8 | "local": "vite --mode localConfig", 9 | "dev": "vite", 10 | "build": "tsc && vite build --mode demo", 11 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 12 | "preview": "vite preview" 13 | }, 14 | "dependencies": { 15 | "@azure/msal-browser": "^3.5.0", 16 | "@azure/msal-react": "^2.0.7", 17 | "@fluentui/react-components": "^9.37.4", 18 | "@microsoft/signalr": "^8.0.0", 19 | "axios": "^1.6.0", 20 | "dotenv": "^16.4.3", 21 | "luxon": "^3.4.3", 22 | "react": "^18.2.0", 23 | "react-dom": "^18.2.0", 24 | "react-markdown": "^9.0.0", 25 | "react-router-dom": "^6.18.0", 26 | "remark-gfm": "^4.0.0", 27 | "remark-supersub": "^1.0.0", 28 | "uuid": "^9.0.1" 29 | }, 30 | "devDependencies": { 31 | "@types/luxon": "^3.4.2", 32 | "@types/react": "^18.2.55", 33 | "@types/react-dom": "^18.2.19", 34 | "@types/uuid": "^9.0.8", 35 | "@typescript-eslint/eslint-plugin": "^6.21.0", 36 | "@typescript-eslint/parser": "^6.21.0", 37 | "@vitejs/plugin-react": "^4.2.1", 38 | "eslint": "^8.56.0", 39 | "eslint-plugin-react-hooks": "^4.6.0", 40 | "eslint-plugin-react-refresh": "^0.4.5", 41 | "typescript": "^5.2.2", 42 | "vite": "^5.3.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .body { 2 | height: 100vh; 3 | background: #f2f2f2; 4 | } 5 | 6 | .app-header { 7 | display: flex; 8 | flex-direction: row; 9 | justify-content: center; 10 | margin-bottom: 4px; 11 | } 12 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { Tab, TabList } from '@fluentui/react-components' 2 | import { Settings } from 'luxon' 3 | import { Route, Routes, createBrowserRouter, useNavigate } from 'react-router-dom' 4 | import './App.css' 5 | import { NavBar } from './components/NavBar/NavBar' 6 | import { ChatPage } from './pages/chat/ChatPage' 7 | 8 | export default function App() { 9 | Settings.defaultLocale = 'en-UK' 10 | 11 | createBrowserRouter([ 12 | { 13 | path: '/', 14 | element: , 15 | }, 16 | { 17 | path: '/chat', 18 | element: , 19 | } 20 | ]) 21 | 22 | const navigate = useNavigate() 23 | 24 | return ( 25 |
26 | 27 |
28 | 29 | navigate('chat')}> 30 | 🗨️ Chat 31 | 32 | 33 |
34 | 35 | 36 | } /> 37 | } /> 38 | 39 |
40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/components/Login/Login.css: -------------------------------------------------------------------------------- 1 | .login-container { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | margin-top: 30px; 6 | } 7 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/components/Login/Login.tsx: -------------------------------------------------------------------------------- 1 | import { IPublicClientApplication } from '@azure/msal-browser' 2 | import { useMsal } from '@azure/msal-react' 3 | import { CompoundButton } from '@fluentui/react-components' 4 | import { GuestRegular } from '@fluentui/react-icons' 5 | import { loginRequest } from '../../security/authConfig' 6 | import './Login.css' 7 | 8 | export function Login() { 9 | const { instance } = useMsal() 10 | 11 | const handleLogin = (instance: IPublicClientApplication) => { 12 | instance.loginRedirect(loginRequest).catch((e) => { 13 | console.error(e) 14 | }) 15 | } 16 | 17 | return ( 18 |
19 | } onClick={() => handleLogin(instance)}> 20 | Please click here to sign in 21 | 22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/components/NavBar/NavBar.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Avatar, 3 | Menu, 4 | MenuButton, 5 | MenuItem, 6 | MenuList, 7 | MenuPopover, 8 | MenuTrigger, 9 | Title3, 10 | makeStyles, 11 | shorthands, 12 | tokens, 13 | } from '@fluentui/react-components' 14 | 15 | const useStyles = makeStyles({ 16 | navBar: { 17 | backgroundColor: tokens.colorBrandBackground, 18 | height: '40px', 19 | display: 'flex', 20 | flexDirection: 'row', 21 | alignItems: 'center', 22 | justifyContent: 'space-between', 23 | ...shorthands.padding('10px'), 24 | }, 25 | title: { 26 | color: tokens.colorNeutralBackground1, 27 | }, 28 | userMenu: { 29 | display: 'flex', 30 | flexDirection: 'row', 31 | alignItems: 'center', 32 | }, 33 | }) 34 | 35 | export interface NavBarProps { 36 | userSignedIn: boolean 37 | } 38 | 39 | export function NavBar() { 40 | const styles = useStyles() 41 | const username = 'User' 42 | 43 | return ( 44 |
45 | Support Center 46 |
47 | 48 | 49 | {username} 50 | 51 | 52 | 53 | 54 | ⚙️ Settings 55 | 56 | 57 | 58 | 59 |
60 |
61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/components/WelcomeHints/WelcomeHints.css: -------------------------------------------------------------------------------- 1 | .welcome-container { 2 | position: relative; 3 | min-height: calc(90vh - 230px); 4 | max-height: calc(90vh - 230px); 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | .hints-container { 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: center; 13 | } 14 | 15 | .warning-container { 16 | position: absolute; 17 | bottom: 0px; 18 | width: 100%; 19 | display: flex; 20 | flex-direction: row; 21 | justify-content: center; 22 | } 23 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 4 | 'Helvetica Neue', sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | } 8 | 9 | code { 10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 11 | } 12 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { FluentProvider, webLightTheme } from '@fluentui/react-components' 2 | import React from 'react' 3 | import ReactDOM from 'react-dom/client' 4 | import { BrowserRouter } from 'react-router-dom' 5 | import App from './App.tsx' 6 | import './index.css' 7 | 8 | ReactDOM.createRoot(document.getElementById('root')!).render( 9 | 10 | 11 | 12 | 13 | 14 | 15 | , 16 | ) 17 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/Citation.ts: -------------------------------------------------------------------------------- 1 | export interface Citation { 2 | id: string 3 | title: string 4 | content: string 5 | filename: string 6 | url: string 7 | reindex_id: string | undefined 8 | } 9 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/Configuration.ts: -------------------------------------------------------------------------------- 1 | export interface ChatConfiguration { 2 | welcomeTitle: string, 3 | welcomeSubtitle: string, 4 | welcomeHints: string[] 5 | welcomeWarning: string, 6 | previewContent: 'Text' | 'File', 7 | } 8 | 9 | export interface Configuration { 10 | chatConfiguration: ChatConfiguration 11 | } 12 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/Conversation.ts: -------------------------------------------------------------------------------- 1 | import { Message } from './Message' 2 | 3 | export interface Conversation { 4 | id: string 5 | metadata: { [key: string]: string } 6 | messages: Message[] 7 | } 8 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/Knowledge.ts: -------------------------------------------------------------------------------- 1 | import { DateTime } from 'luxon' 2 | 3 | export interface Knowledge { 4 | status: string 5 | lastEndTime: DateTime 6 | } 7 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/KnowledgeDocument.ts: -------------------------------------------------------------------------------- 1 | import { DateTime } from 'luxon' 2 | 3 | export interface KnowledgeDocument { 4 | fileName: string 5 | lastModified: DateTime 6 | grantedUserId: string 7 | } 8 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/models/Message.tsx: -------------------------------------------------------------------------------- 1 | import { Citation } from './Citation' 2 | 3 | export interface Message { 4 | id: string 5 | conversationId: string 6 | userId: string 7 | sender: SenderType 8 | text: string 9 | timestamp: Date 10 | citations: undefined | Citation[] 11 | feedback: undefined | -1 | 1 12 | isError: boolean 13 | } 14 | 15 | export enum SenderType { 16 | User = 'User', 17 | // Generic agent type 18 | Agent = 'Agent', 19 | Dispatcher = 'Dispatcher', 20 | CustomerInfo = 'CustomerInfo', 21 | Notification = 'Notification', 22 | Discount = 'Discount', 23 | Invoice = 'Invoice', 24 | QnA = 'QnA', 25 | ErrorNotification = 'ErrorNotification', 26 | // Agent-specific notification types 27 | DispatcherNotification = 'DispatcherNotification', 28 | CustomerInfoNotification = 'CustomerInfoNotification', 29 | AgentInfoNotification = 'AgentInfoNotification' 30 | } -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/PageStyles.ts: -------------------------------------------------------------------------------- 1 | import { makeStyles, shorthands, tokens } from '@fluentui/react-components' 2 | 3 | export const pageStyles = makeStyles({ 4 | sectionContainer: { 5 | ...shorthands.borderRadius(tokens.borderRadiusLarge), 6 | ...shorthands.margin('10px'), 7 | ...shorthands.padding('15px'), 8 | backgroundColor: tokens.colorNeutralBackground1, 9 | boxShadow: tokens.shadow4, 10 | }, 11 | }) 12 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/chat/components/ChatHistoryList/ChatHistoryList.css: -------------------------------------------------------------------------------- 1 | .messages-container { 2 | overflow: hidden auto; 3 | min-height: calc(90vh - 250px); 4 | max-height: calc(90vh - 250px); 5 | padding: 10px; 6 | } 7 | 8 | .copilot-message-container, 9 | .user-message-container { 10 | display: flex; 11 | flex-direction: row; 12 | align-items: center; 13 | } 14 | 15 | .copilot-message-container { 16 | justify-content: flex-start; 17 | } 18 | 19 | .user-message-container { 20 | justify-content: flex-end; 21 | } 22 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/chat/components/ChatHistoryList/ChatHistoryList.tsx: -------------------------------------------------------------------------------- 1 | import { useContext, useEffect, useRef } from 'react' 2 | import { SenderType } from '../../../../models/Message' 3 | import { ChatFeatureContext } from '../../../../states/ChatContext' 4 | import { ChatMessage } from '../ChatMessage/ChatMessage' 5 | import './ChatHistoryList.css' 6 | 7 | export function ChatHistoryList() { 8 | const context = useContext(ChatFeatureContext) 9 | 10 | // Scrolling to the bottom of the list when a new message is added 11 | const messagesEnd = useRef(null) 12 | useEffect(() => messagesEnd?.current?.scrollIntoView({ behavior: 'smooth' }), [context.conversation.messages]) 13 | 14 | return ( 15 |
16 | {context.conversation.messages.map((message) => ( 17 |
18 | 19 |
20 | ))} 21 | 22 |
23 |
24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/chat/components/ChatInputBox/ChatInputBox.css: -------------------------------------------------------------------------------- 1 | .input-toolbar { 2 | display: flex; 3 | flex-direction: row; 4 | justify-content: space-between; 5 | align-items: center; 6 | width: 100%; 7 | margin-top: 10px; 8 | } 9 | 10 | .input-message { 11 | width: 100%; 12 | height: 70px; 13 | } 14 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/chat/components/ChatMessage/ChatMessage.css: -------------------------------------------------------------------------------- 1 | .user-message-card { 2 | background-color: '#EDF5FD'; 3 | } 4 | 5 | .message-container { 6 | display: flex; 7 | flex-direction: row; 8 | align-items: flex-start; 9 | margin: 10px 0px; 10 | } 11 | 12 | .message-container-footer { 13 | display: flex; 14 | flex-direction: row; 15 | justify-content: space-between; 16 | align-items: center; 17 | width: 100%; 18 | } 19 | 20 | .feedback-container-target { 21 | display: flex; 22 | flex-direction: row-reverse; 23 | margin: 0px 30px; 24 | } 25 | 26 | .message-disclaimer { 27 | color: #707070; 28 | } 29 | 30 | .citation-container { 31 | flex-direction: column; 32 | } 33 | 34 | .citation-item { 35 | margin: 2px 0px; 36 | } 37 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/pages/chat/components/ChatMessage/MessageParser.tsx: -------------------------------------------------------------------------------- 1 | import { Citation } from '../../../../models/Citation' 2 | import { Message } from '../../../../models/Message' 3 | 4 | export function parseMessage(message: Message | undefined): Message | undefined { 5 | if (!message) { 6 | return undefined 7 | } 8 | 9 | let parsedText = message.text 10 | const citationLinks = parsedText.match(/\[(doc\d\d?\d?)]/g) 11 | 12 | const lengthDocN = '[doc'.length 13 | 14 | const filteredCitations: Citation[] = [] 15 | let citationReindex = 0 16 | citationLinks?.forEach((link) => { 17 | // Replacing the links/citations with number 18 | const citationIndex = link.slice(lengthDocN, link.length - 1) 19 | if (!citationIndex || !message.citations || message.citations.length < Number(citationIndex)) { 20 | return 21 | } 22 | const citation = { ...message.citations[Number(citationIndex) - 1] } 23 | if (!filteredCitations.find((c) => c.id === citationIndex)) { 24 | parsedText = parsedText.replaceAll(link, ` ^${++citationReindex}^ `) 25 | citation.id = citationIndex // original doc index to de-dupe 26 | citation.reindex_id = citationReindex.toString() // reindex from 1 for display 27 | filteredCitations.push(citation) 28 | } 29 | }) 30 | 31 | return { 32 | ...message, 33 | text: parsedText, 34 | citations: filteredCitations, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/states/AppContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react' 2 | import { Configuration } from '../models/Configuration' 3 | 4 | export interface AppContext { 5 | configuration: Configuration 6 | } 7 | 8 | export const appInitialContext: AppContext = { 9 | configuration: {} as Configuration, 10 | } 11 | 12 | export const AppFeatureContext = createContext(appInitialContext) 13 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/states/ChatContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react' 2 | import { Citation } from '../models/Citation' 3 | import { Conversation } from '../models/Conversation' 4 | import { Message } from '../models/Message' 5 | 6 | export interface ChatContext { 7 | conversation: Conversation 8 | citationPreview: Citation | undefined 9 | isLoading: boolean 10 | isTakingTooLong: boolean 11 | waitingMessage: string 12 | } 13 | 14 | export const initialContext: ChatContext = { 15 | conversation: { 16 | id: '', 17 | metadata: {}, 18 | messages: [], 19 | }, 20 | citationPreview: undefined, 21 | isLoading: false, 22 | isTakingTooLong: false, 23 | waitingMessage: '' 24 | } 25 | 26 | export const ChatFeatureContext = createContext(initialContext) 27 | 28 | export interface ChatContextHandler { 29 | onRestartConversation: () => void 30 | onSendMessage: (messageText: string) => void 31 | onCitationPreview: (citation: Citation) => void 32 | onSendFeedback: (message: Message, feedback: -1 | 1) => void 33 | } 34 | 35 | export const initialContextHandler: ChatContextHandler = { 36 | onRestartConversation: () => new Error('onRestartConversation is not initialized'), 37 | onSendMessage: () => new Error('onSendMessage is not initialized'), 38 | onCitationPreview: () => new Error('onCitationPreview is not initialized'), 39 | onSendFeedback: () => new Error('onSendFeedback is not initialized'), 40 | } 41 | 42 | export const ChatFeatureContextHandler = createContext(initialContextHandler) 43 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | interface ImportMetaEnv { 4 | readonly VITE_APP_TITLE: string 5 | readonly VITE_OAGENT_CLIENT_ID: string 6 | readonly VITE_OAGENT_BASE_URL: string 7 | readonly VITE_IS_MOCK_ENABLED: boolean 8 | } 9 | 10 | interface ImportMeta { 11 | readonly env: ImportMetaEnv 12 | } 13 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "ES2021.String", "DOM", "DOM.Iterable", "WebWorker"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /samples/support-center/src/frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 3000, 9 | } 10 | }); -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/AgentState.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.Agents.Abstractions; 2 | 3 | public class AgentState where T: class, new() 4 | { 5 | public List History { get; set; } 6 | public T Data { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/ChatHistoryItem.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.Agents.Abstractions; 2 | 3 | [Serializable] 4 | public class ChatHistoryItem 5 | { 6 | public string Message { get; set; } 7 | public ChatUserType UserType { get; set; } 8 | public int Order { get; set; } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/ChatUserType.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.Agents.Abstractions; 2 | 3 | public enum ChatUserType 4 | { 5 | System, 6 | User, 7 | Agent 8 | } -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/Event.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | 3 | namespace Microsoft.AI.Agents.Abstractions 4 | { 5 | [DataContract] 6 | public class Event 7 | { 8 | public Dictionary Data { get; set; } 9 | public string Type { get; set; } 10 | public string Subject { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/IAgent.cs: -------------------------------------------------------------------------------- 1 | namespace Microsoft.AI.Agents.Abstractions; 2 | 3 | public interface IAgent 4 | { 5 | Task HandleEvent(Event item); 6 | Task PublishEvent(string ns, string id, Event item); 7 | } -------------------------------------------------------------------------------- /src/Oagents.Core/Abstractions/IAiAgent.cs: -------------------------------------------------------------------------------- 1 | 2 | using Microsoft.SemanticKernel; 3 | using Microsoft.SemanticKernel.Connectors.OpenAI; 4 | 5 | namespace Microsoft.AI.Agents.Abstractions; 6 | 7 | public interface IAiAgent : IAgent 8 | { 9 | void AddToHistory(string message, ChatUserType userType); 10 | string AppendChatHistory(string ask); 11 | Task CallFunction(string template, KernelArguments arguments, OpenAIPromptExecutionSettings? settings = null); 12 | Task AddKnowledge(string instruction, string index, KernelArguments arguments); 13 | } -------------------------------------------------------------------------------- /src/Oagents.Core/Oagents.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | Oagents.Core 8 | https://github.com/microsoft/project-oagents 9 | kostapetan 10 | Oagents Core Library 11 | ai-agents;event-driven-agents 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Oagents.Dapr/Agent.cs: -------------------------------------------------------------------------------- 1 | using Dapr.Actors.Runtime; 2 | using Dapr.Client; 3 | using Microsoft.AI.Agents.Abstractions; 4 | 5 | namespace Microsoft.AI.Agents.Dapr; 6 | 7 | public abstract class Agent : Actor, IAgent 8 | { 9 | private readonly DaprClient daprClient; 10 | 11 | protected Agent(ActorHost host, DaprClient daprClient) : base(host) 12 | { 13 | this.daprClient = daprClient; 14 | } 15 | public abstract Task HandleEvent(Event item); 16 | 17 | public async Task PublishEvent(string ns, string id, Event item) 18 | { 19 | var metadata = new Dictionary() { 20 | { "cloudevent.Type", item.Type }, 21 | { "cloudevent.Subject", item.Subject }, 22 | { "cloudevent.id", Guid.NewGuid().ToString()} 23 | }; 24 | 25 | await daprClient.PublishEventAsync(ns, id, item, metadata); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Oagents.Dapr/IDaprAgent.cs: -------------------------------------------------------------------------------- 1 | using Dapr.Actors; 2 | using Microsoft.AI.Agents.Abstractions; 3 | 4 | namespace Microsoft.AI.Agents.Dapr; 5 | 6 | public interface IDaprAgent : IActor 7 | { 8 | Task HandleEvent(Event item); 9 | } -------------------------------------------------------------------------------- /src/Oagents.Dapr/Oagents.Dapr.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | Oagents.Dapr 8 | https://github.com/microsoft/project-oagents 9 | kostapetan 10 | Oagents - Dapr implementation 11 | ai-agents;event-driven-agents 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Oagents.Orleans/Agent.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | using Orleans.Runtime; 3 | using Orleans.Streams; 4 | 5 | namespace Microsoft.AI.Agents.Orleans; 6 | 7 | public abstract class Agent : Grain, IGrainWithStringKey, IAgent 8 | { 9 | protected virtual string Namespace { get; set; } 10 | public abstract Task HandleEvent(Event item); 11 | 12 | private async Task HandleEvent(Event item, StreamSequenceToken? token) 13 | { 14 | await HandleEvent(item); 15 | } 16 | 17 | public async Task PublishEvent(string ns, string id, Event item) 18 | { 19 | var streamProvider = this.GetStreamProvider("StreamProvider"); 20 | var streamId = StreamId.Create(ns, id); 21 | var stream = streamProvider.GetStream(streamId); 22 | await stream.OnNextAsync(item); 23 | } 24 | 25 | public async override Task OnActivateAsync(CancellationToken cancellationToken) 26 | { 27 | var streamProvider = this.GetStreamProvider("StreamProvider"); 28 | var streamId = StreamId.Create(Namespace, this.GetPrimaryKeyString()); 29 | var stream = streamProvider.GetStream(streamId); 30 | await stream.SubscribeAsync(HandleEvent); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Oagents.Orleans/EventSurrogate.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AI.Agents.Abstractions; 2 | 3 | namespace Microsoft.AI.Agents.Orleans; 4 | 5 | [GenerateSerializer] 6 | public struct EventSurrogate 7 | { 8 | [Id(0)] 9 | public Dictionary Data { get; set; } 10 | [Id(1)] 11 | public string Type { get; set; } 12 | [Id(2)] 13 | public string Subject { get; set; } 14 | } 15 | 16 | [RegisterConverter] 17 | public sealed class EventSurrogateConverter : 18 | IConverter 19 | { 20 | public Event ConvertFromSurrogate( 21 | in EventSurrogate surrogate) => 22 | new Event { Data = surrogate.Data, Subject = surrogate.Subject, Type = surrogate.Type}; 23 | 24 | public EventSurrogate ConvertToSurrogate( 25 | in Event value) => 26 | new EventSurrogate 27 | { 28 | Data = value.Data, 29 | Type = value.Type, 30 | Subject = value.Subject 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /src/Oagents.Orleans/Oagents.Orleans.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | Oagents.Orleans 8 | https://github.com/microsoft/project-oagents 9 | kostapetan 10 | Oagents - Orleans implementation 11 | ai-agents;event-driven-agents; Orleans 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Oagents.Orleans/Resolvers.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SemanticKernel.Memory; 2 | using Microsoft.SemanticKernel; 3 | 4 | namespace Microsoft.AI.Agents.Orleans 5 | { 6 | public class Resolvers 7 | { 8 | public delegate Kernel KernelResolver(string agent); 9 | public delegate ISemanticTextMemory SemanticTextMemoryResolver(string agent); 10 | } 11 | } 12 | --------------------------------------------------------------------------------