├── .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 | 
10 |
11 | 
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 |
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 |
--------------------------------------------------------------------------------