├── .devcontainer └── devcontainer.json ├── .gitattributes ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── aca-deploy.yaml │ ├── acr-build-push.yaml │ ├── azure-dev.yaml │ └── infra-ci.yaml ├── .gitignore ├── CHANGELOG.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── README.md ├── SECURITY.md ├── app ├── business-api │ ├── account │ │ ├── .mvn │ │ │ └── wrapper │ │ │ │ └── maven-wrapper.properties │ │ ├── Dockerfile │ │ ├── applicationinsights.json │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── microsoft │ │ │ │ │ └── openai │ │ │ │ │ └── samples │ │ │ │ │ └── assistant │ │ │ │ │ └── business │ │ │ │ │ ├── AccountApplication.java │ │ │ │ │ ├── controller │ │ │ │ │ ├── AccountController.java │ │ │ │ │ └── UserController.java │ │ │ │ │ ├── mcp │ │ │ │ │ ├── config │ │ │ │ │ │ └── MCPServerConfiguration.java │ │ │ │ │ └── server │ │ │ │ │ │ ├── AccountMCPService.java │ │ │ │ │ │ └── UserMCPService.java │ │ │ │ │ ├── models │ │ │ │ │ ├── Account.java │ │ │ │ │ ├── Beneficiary.java │ │ │ │ │ ├── PaymentMethod.java │ │ │ │ │ └── PaymentMethodSummary.java │ │ │ │ │ └── service │ │ │ │ │ ├── AccountService.java │ │ │ │ │ └── UserService.java │ │ │ └── resources │ │ │ │ ├── account.yaml │ │ │ │ └── application-dev.properties │ │ │ └── test │ │ │ └── java │ │ │ └── org │ │ │ └── springframework │ │ │ └── ai │ │ │ └── mcp │ │ │ └── sample │ │ │ └── client │ │ │ └── AccountMCPClient.java │ ├── payment │ │ ├── .mvn │ │ │ └── wrapper │ │ │ │ └── maven-wrapper.properties │ │ ├── Dockerfile │ │ ├── applicationinsights.json │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── assistant │ │ │ │ └── business │ │ │ │ ├── PaymentApplication.java │ │ │ │ ├── controller │ │ │ │ └── PaymentsController.java │ │ │ │ ├── mcp │ │ │ │ ├── config │ │ │ │ │ └── MCPServerConfiguration.java │ │ │ │ └── server │ │ │ │ │ └── PaymentMCPService.java │ │ │ │ ├── models │ │ │ │ ├── Payment.java │ │ │ │ └── Transaction.java │ │ │ │ └── service │ │ │ │ └── PaymentService.java │ │ │ └── resources │ │ │ ├── application-dev.properties │ │ │ ├── application.properties │ │ │ ├── payments.yaml │ │ │ └── transaction-history.yaml │ └── transactions-history │ │ ├── .mvn │ │ └── wrapper │ │ │ └── maven-wrapper.properties │ │ ├── Dockerfile │ │ ├── applicationinsights.json │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── microsoft │ │ │ └── openai │ │ │ └── samples │ │ │ └── assistant │ │ │ └── business │ │ │ ├── Transaction.java │ │ │ ├── TransactionController.java │ │ │ ├── TransactionService.java │ │ │ ├── TransactionsHistoryApplication.java │ │ │ └── mcp │ │ │ ├── config │ │ │ └── MCPServerConfiguration.java │ │ │ └── server │ │ │ └── TransactionMCPService.java │ │ └── resources │ │ ├── application-dev.properties │ │ └── transaction-history.yaml ├── compose.yaml ├── copilot │ ├── .mvn │ │ ├── jvm.config │ │ └── wrapper │ │ │ └── maven-wrapper.properties │ ├── Dockerfile │ ├── applicationinsights.json │ ├── copilot-backend │ │ ├── manifests │ │ │ ├── azd-env-configmap.yml │ │ │ ├── backend-deployment.tmpl.yml │ │ │ ├── backend-service.yml │ │ │ └── ingress.yml │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── microsoft │ │ │ │ │ └── openai │ │ │ │ │ └── samples │ │ │ │ │ └── assistant │ │ │ │ │ ├── CopilotApplication.java │ │ │ │ │ ├── common │ │ │ │ │ └── ChatGPTMessage.java │ │ │ │ │ ├── config │ │ │ │ │ ├── AzureAuthenticationConfiguration.java │ │ │ │ │ ├── AzureOpenAIConfiguration.java │ │ │ │ │ ├── BlobStorageProxyConfiguration.java │ │ │ │ │ ├── DocumentIntelligenceConfiguration.java │ │ │ │ │ ├── DocumentIntelligenceInvoiceScanConfiguration.java │ │ │ │ │ ├── Langchain4JConfiguration.java │ │ │ │ │ └── MCPAgentsConfiguration.java │ │ │ │ │ ├── controller │ │ │ │ │ ├── ChatAppRequest.java │ │ │ │ │ ├── ChatAppRequestContext.java │ │ │ │ │ ├── ChatAppRequestOverrides.java │ │ │ │ │ ├── ChatController.java │ │ │ │ │ ├── ChatResponse.java │ │ │ │ │ ├── ResponseChoice.java │ │ │ │ │ ├── ResponseContext.java │ │ │ │ │ ├── ResponseMessage.java │ │ │ │ │ ├── auth │ │ │ │ │ │ └── AuthSetup.java │ │ │ │ │ └── content │ │ │ │ │ │ └── ContentController.java │ │ │ │ │ ├── plugin │ │ │ │ │ ├── InvoiceScanPlugin.java.sample │ │ │ │ │ ├── LoggedUserPlugin.java.sample │ │ │ │ │ ├── PaymentMockPlugin.java.sample │ │ │ │ │ ├── TransactionHistoryMockPlugin.java.sample │ │ │ │ │ └── mock │ │ │ │ │ │ ├── PaymentTransaction.java │ │ │ │ │ │ └── TransactionServiceMock.java │ │ │ │ │ ├── proxy │ │ │ │ │ └── OpenAIProxy.java │ │ │ │ │ └── security │ │ │ │ │ ├── LoggedUser.java │ │ │ │ │ └── LoggedUserService.java │ │ │ └── resources │ │ │ │ ├── account.yaml │ │ │ │ ├── application.properties │ │ │ │ ├── payments.yaml │ │ │ │ └── transaction-history.yaml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── microsoft │ │ │ └── openai │ │ │ └── samples │ │ │ └── assistant │ │ │ └── AccountAgentIntegrationTest.java │ ├── copilot-common │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── microsoft │ │ │ └── openai │ │ │ └── samples │ │ │ └── assistant │ │ │ ├── invoice │ │ │ └── DocumentIntelligenceInvoiceScanHelper.java │ │ │ └── proxy │ │ │ └── BlobStorageProxy.java │ ├── langchain4j-agents │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── microsoft │ │ │ │ ├── langchain4j │ │ │ │ └── agent │ │ │ │ │ ├── AbstractReActAgent.java │ │ │ │ │ ├── Agent.java │ │ │ │ │ ├── AgentExecutionException.java │ │ │ │ │ ├── AgentMetadata.java │ │ │ │ │ └── mcp │ │ │ │ │ ├── MCPProtocolType.java │ │ │ │ │ ├── MCPServerMetadata.java │ │ │ │ │ └── MCPToolAgent.java │ │ │ │ └── openai │ │ │ │ └── samples │ │ │ │ └── assistant │ │ │ │ └── langchain4j │ │ │ │ ├── agent │ │ │ │ ├── SupervisorAgent.java │ │ │ │ └── mcp │ │ │ │ │ ├── AccountMCPAgent.java │ │ │ │ │ ├── PaymentMCPAgent.java │ │ │ │ │ └── TransactionHistoryMCPAgent.java │ │ │ │ └── tools │ │ │ │ └── InvoiceScanTool.java │ │ │ └── test │ │ │ ├── java │ │ │ └── dev │ │ │ │ └── langchain4j │ │ │ │ └── openapi │ │ │ │ └── mcp │ │ │ │ ├── AccountMCPAgentIntegrationTest.java │ │ │ │ ├── PaymentMCPAgentIntegrationTest.java │ │ │ │ ├── PaymentMCPAgentIntegrationWithImageTest.java │ │ │ │ ├── SupervisorAgentLongConversationIntegrationTest.java │ │ │ │ ├── SupervisorAgentNoRoutingIntegrationTest.java │ │ │ │ ├── SupervisorAgentRoutingIntegrationTest.java │ │ │ │ └── TransactionHistoryMCPAgentIntegrationTest.java │ │ │ └── resources │ │ │ ├── account.yaml │ │ │ ├── logback.xml │ │ │ ├── payments.yaml │ │ │ └── transaction-history.yaml │ ├── mvnw │ ├── mvnw.cmd │ └── pom.xml ├── frontend │ ├── .dockerignore │ ├── .env.dev │ ├── .env.local │ ├── .env.production │ ├── .npmrc │ ├── .prettierignore │ ├── .prettierrc.json │ ├── Dockerfile │ ├── Dockerfile-aks │ ├── index.html │ ├── manifests │ │ ├── frontend-deployment.tmpl.yml │ │ └── frontend-service.yml │ ├── nginx │ │ └── nginx.conf.template │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── api │ │ │ ├── api.ts │ │ │ ├── index.ts │ │ │ └── models.ts │ │ ├── assets │ │ │ ├── github.svg │ │ │ └── search.svg │ │ ├── authConfig.ts │ │ ├── components │ │ │ ├── AnalysisPanel │ │ │ │ ├── AnalysisPanel.module.css │ │ │ │ ├── AnalysisPanel.tsx │ │ │ │ ├── AnalysisPanelTabs.tsx │ │ │ │ └── index.tsx │ │ │ ├── Answer │ │ │ │ ├── Answer.module.css │ │ │ │ ├── Answer.tsx │ │ │ │ ├── AnswerError.tsx │ │ │ │ ├── AnswerIcon.tsx │ │ │ │ ├── AnswerLoading.tsx │ │ │ │ ├── AnswerParser.tsx │ │ │ │ └── index.ts │ │ │ ├── AttachmentType.ts │ │ │ ├── ClearChatButton │ │ │ │ ├── ClearChatButton.module.css │ │ │ │ ├── ClearChatButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── Example │ │ │ │ ├── Example.module.css │ │ │ │ ├── Example.tsx │ │ │ │ ├── ExampleList.tsx │ │ │ │ └── index.tsx │ │ │ ├── LoginButton │ │ │ │ ├── LoginButton.module.css │ │ │ │ ├── LoginButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── QuestionInput │ │ │ │ ├── QuestionContext.ts │ │ │ │ ├── QuestionInput.module.css │ │ │ │ ├── QuestionInput.tsx │ │ │ │ └── index.ts │ │ │ ├── SettingsButton │ │ │ │ ├── SettingsButton.module.css │ │ │ │ ├── SettingsButton.tsx │ │ │ │ └── index.tsx │ │ │ ├── SupportingContent │ │ │ │ ├── SupportingContent.module.css │ │ │ │ ├── SupportingContent.tsx │ │ │ │ ├── SupportingContentParser.ts │ │ │ │ └── index.ts │ │ │ ├── TokenClaimsDisplay │ │ │ │ ├── TokenClaimsDisplay.tsx │ │ │ │ └── index.tsx │ │ │ └── UserChatMessage │ │ │ │ ├── UserChatMessage.module.css │ │ │ │ ├── UserChatMessage.tsx │ │ │ │ └── index.ts │ │ ├── index.css │ │ ├── index.tsx │ │ ├── pages │ │ │ ├── NoPage.tsx │ │ │ ├── chat │ │ │ │ ├── Chat.module.css │ │ │ │ └── Chat.tsx │ │ │ └── layout │ │ │ │ ├── Layout.module.css │ │ │ │ └── Layout.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.ts ├── package-lock.json ├── start-compose.ps1 └── start-compose.sh ├── azure.yaml ├── data ├── eventbrite.png └── gori.png ├── docs ├── assets │ ├── HLA-MCP.png │ ├── HLA.png │ ├── azd-success.png │ ├── java.png │ ├── langchain4j.png │ ├── multi-agents.png │ ├── robot-agents-small.png │ ├── robot-agents.png │ ├── transaction-tracing.png │ └── ui.gif ├── faq.md ├── kusto-queries.md ├── multi-agents │ └── introduction.md └── troubleshooting.md └── infra ├── app ├── account.bicep ├── copilot.bicep ├── payment.bicep ├── transaction.bicep └── web.bicep ├── main.bicep ├── main.parameters.json └── shared ├── abbreviations.json ├── ai └── cognitiveservices.bicep ├── backend-dashboard.bicep ├── host ├── container-app-upsert.bicep ├── container-app.bicep ├── container-apps-environment.bicep ├── container-apps.bicep └── container-registry.bicep ├── monitor ├── applicationinsights-dashboard.bicep ├── applicationinsights.bicep ├── loganalytics.bicep └── monitoring.bicep ├── security ├── keyvault-access.bicep ├── keyvault-secret.bicep ├── keyvault.bicep ├── registry-access.bicep └── role.bicep └── storage └── storage-account.bicep /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Java 17 and maven 3.8.8 DevContainer to build Java RAG example with Azure AI", 3 | "image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye", 4 | "features": { 5 | "azure-cli": "latest", 6 | "ghcr.io/azure/azure-dev/azd:latest": { 7 | "version": "1.9.1" 8 | }, 9 | "ghcr.io/devcontainers/features/java:1": { 10 | "version": "none", 11 | "installMaven": true, 12 | "mavenVersion": "3.8.8" 13 | }, 14 | "ghcr.io/devcontainers/features/node:1": { 15 | "version": "20.5.0" 16 | }, 17 | 18 | "ghcr.io/devcontainers/features/git:1": { 19 | "version": "2.39.1" 20 | }, 21 | "ghcr.io/devcontainers-contrib/features/typescript:2": {}, 22 | "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}, 23 | "docker-in-docker": { 24 | "version": "latest", 25 | "moby": true, 26 | "dockerDashComposeVersion": "v1" 27 | } 28 | }, 29 | "customizations": { 30 | "vscode": { 31 | "extensions": [ 32 | "GitHub.vscode-github-actions", 33 | "ms-azuretools.azure-dev", 34 | "ms-azuretools.vscode-bicep", 35 | "vscjava.vscode-java-pack", 36 | "amodio.tsl-problem-matcher" 37 | ] 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | > Please provide us with the following information: 5 | > --------------------------------------------------------------- 6 | 7 | ### This issue is for a: (mark with an `x`) 8 | ``` 9 | - [ ] bug report -> please search issues before submitting 10 | - [ ] feature request 11 | - [ ] documentation issue or request 12 | - [ ] regression (a behavior that used to work and stopped in a new release) 13 | ``` 14 | 15 | ### Minimal steps to reproduce 16 | > 17 | 18 | ### Any log messages given by the failure 19 | > 20 | 21 | ### Expected/desired behavior 22 | > 23 | 24 | ### OS and Version? 25 | > Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) 26 | 27 | ### azd version? 28 | > run `azd version` and copy paste here. 29 | 30 | ### Versions 31 | > 32 | 33 | ### Mention any other details that might be useful 34 | 35 | > --------------------------------------------------------------- 36 | > Thanks! We'll be in touch soon. 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | * ... 4 | 5 | ## Does this introduce a breaking change? 6 | 7 | ``` 8 | [ ] Yes 9 | [ ] No 10 | ``` 11 | 12 | ## Pull Request Type 13 | What kind of change does this Pull Request introduce? 14 | 15 | 16 | ``` 17 | [ ] Bugfix 18 | [ ] Feature 19 | [ ] Code style update (formatting, local variables) 20 | [ ] Refactoring (no functional changes, no api changes) 21 | [ ] Documentation content changes 22 | [ ] Other... Please describe: 23 | ``` 24 | 25 | ## How to Test 26 | * Get the code 27 | 28 | ``` 29 | git clone [repo-address] 30 | cd [repo-name] 31 | git checkout [branch-name] 32 | npm install 33 | ``` 34 | 35 | * Test the code 36 | 37 | ``` 38 | ``` 39 | 40 | ## What to Check 41 | Verify that the following are valid 42 | * ... 43 | 44 | ## Other Information 45 | -------------------------------------------------------------------------------- /.github/workflows/aca-deploy.yaml: -------------------------------------------------------------------------------- 1 | name: Reusable Azure Container Apps deploy 2 | on: 3 | workflow_call: 4 | inputs: 5 | env-name: 6 | required: true 7 | type: string 8 | image-name: 9 | required: true 10 | type: string 11 | container-app-name: 12 | required: true 13 | type: string 14 | container-app-env-name: 15 | required: true 16 | type: string 17 | 18 | # Set up permissions for deploying with secretless Azure federated credentials 19 | # https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication 20 | permissions: 21 | id-token: write 22 | contents: read 23 | 24 | jobs: 25 | deploy: 26 | runs-on: ubuntu-latest 27 | environment: ${{inputs.env-name}} 28 | steps: 29 | - name: Log in to Azure with service principal 30 | uses: azure/login@v2 31 | if: ${{ vars.AZURE_CLIENT_ID == '' }} 32 | with: 33 | creds: ${{ secrets.AZURE_CREDENTIALS }} 34 | - name: Log in with Azure (Federated Credentials) 35 | if: ${{ vars.AZURE_CLIENT_ID != '' }} 36 | uses: azure/login@v2 37 | with: 38 | client-id: ${{ vars.AZURE_CLIENT_ID }} 39 | tenant-id: ${{ vars.AZURE_TENANT_ID }} 40 | subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} 41 | - name: Build and deploy Container App 42 | uses: azure/container-apps-deploy-action@v1 43 | with: 44 | acrName: ${{vars.ACR_NAME}} 45 | containerAppName: ${{inputs.container-app-name}} 46 | containerAppEnvironment: ${{inputs.container-app-env-name}} 47 | resourceGroup: ${{vars.RESOURCE_GROUP}} 48 | imageToDeploy: ${{vars.ACR_NAME}}.azurecr.io/${{inputs.image-name}}:${{github.sha}} -------------------------------------------------------------------------------- /.github/workflows/acr-build-push.yaml: -------------------------------------------------------------------------------- 1 | name: Reusable ACR Build and Push workflow 2 | on: 3 | workflow_call: 4 | inputs: 5 | env-name: 6 | required: true 7 | type: string 8 | image-name: 9 | required: true 10 | type: string 11 | app-folder-path: 12 | required: true 13 | type: string 14 | 15 | # Set up permissions for deploying with secretless Azure federated credentials 16 | # https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-portal%2Clinux#set-up-azure-login-with-openid-connect-authentication 17 | permissions: 18 | id-token: write 19 | contents: read 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | environment: ${{inputs.env-name}} 25 | 26 | steps: 27 | - name: Log in to Azure with service principal 28 | if: ${{ vars.AZURE_CLIENT_ID == '' }} 29 | uses: azure/login@v2 30 | with: 31 | creds: ${{ secrets.AZURE_CREDENTIALS }} 32 | - name: Log in Azure Container Registry 33 | if: ${{ vars.AZURE_CLIENT_ID == '' }} 34 | uses: azure/docker-login@v2 35 | with: 36 | login-server: ${{vars.ACR_NAME}}.azurecr.io 37 | username: ${{ secrets.SPI_CLIENT_ID }} 38 | password: ${{ secrets.SPI_CLIENT_SECRET }} 39 | - name: Log in with Azure (Federated Credentials) 40 | if: ${{ vars.AZURE_CLIENT_ID != '' }} 41 | uses: azure/login@v2 42 | with: 43 | client-id: ${{ vars.AZURE_CLIENT_ID }} 44 | tenant-id: ${{ vars.AZURE_TENANT_ID }} 45 | subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} 46 | - name: Login to Azure Container Registry (Federated Credentials) 47 | if: ${{ vars.AZURE_CLIENT_ID != '' }} 48 | run: az acr login --name ${{vars.ACR_NAME}} 49 | - uses: actions/checkout@v2 50 | - name: Build and Push to ACR 51 | run: | 52 | echo "Building image [${{ inputs.image-name }}] and environment [${{ inputs.env-name }}]" 53 | cd ${{ inputs.app-folder-path }} 54 | docker build . -t ${{vars.ACR_NAME}}.azurecr.io/${{inputs.image-name}}:${{github.sha}} 55 | docker push ${{vars.ACR_NAME}}.azurecr.io/${{inputs.image-name}}:${{github.sha}} 56 | echo "image successfully pushed: ${{vars.ACR_NAME}}.azurecr.io/${{inputs.image-name}}:${{github.sha}}" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [project-title] Changelog 2 | 3 | 4 | # x.y.z (yyyy-mm-dd) 5 | 6 | *Features* 7 | * ... 8 | 9 | *Bug Fixes* 10 | * ... 11 | 12 | *Breaking Changes* 13 | * ... 14 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in 2 | # this repo. Unless a later match takes precedence, 3 | # @global-owner1 and @global-owner2 will be requested for 4 | # review when someone opens a pull request. 5 | * @dantelmomsft 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Azure Samples 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 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | - Full paths of source file(s) related to the manifestation of the issue 23 | - The location of the affected source code (tag/branch/commit or direct URL) 24 | - Any special configuration required to reproduce the issue 25 | - Step-by-step instructions to reproduce the issue 26 | - Proof-of-concept or exploit code (if possible) 27 | - Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/business-api/account/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip 20 | -------------------------------------------------------------------------------- /app/business-api/account/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build 2 | 3 | WORKDIR /workspace/app 4 | EXPOSE 3100 5 | 6 | COPY mvnw . 7 | COPY .mvn .mvn 8 | COPY pom.xml . 9 | COPY src src 10 | 11 | RUN chmod +x ./mvnw 12 | # Convert CRLF to LF 13 | RUN sed -i 's/\r$//' ./mvnw 14 | RUN ./mvnw package -DskipTests 15 | RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) 16 | 17 | RUN apt-get update && apt-get install -y curl 18 | RUN curl -LJ -o applicationinsights-agent-3.5.4.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.5.4/applicationinsights-agent-3.5.4.jar 19 | COPY applicationinsights.json . 20 | 21 | #for production deployment use mcr.microsoft.com/openjdk/jdk:17-distroless 22 | FROM mcr.microsoft.com/openjdk/jdk:17-distroless 23 | 24 | ARG DEPENDENCY=/workspace/app/target/dependency 25 | COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib 26 | COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF 27 | COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app 28 | COPY --from=build /workspace/app/applicationinsights-agent-3.5.4.jar /app 29 | COPY --from=build /workspace/app/applicationinsights.json /app 30 | 31 | EXPOSE 8080 32 | 33 | ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.5.4.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.assistant.business.AccountApplication"] -------------------------------------------------------------------------------- /app/business-api/account/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "role": { 3 | "name": "accounts-api" 4 | } 5 | } -------------------------------------------------------------------------------- /app/business-api/account/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.6 9 | 10 | 11 | com.microsoft.openai.samples.assistant.business 12 | account 13 | 1.0.0-SNAPSHOT 14 | 15 | 16 | 17 17 | 17 18 | UTF-8 19 | 20 | 21 | 22 | 23 | 24 | 25 | org.springframework.ai 26 | spring-ai-bom 27 | 1.0.0-SNAPSHOT 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | 36 | org.springframework.ai 37 | spring-ai-starter-mcp-server-webmvc 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-web 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-maven-plugin 50 | 51 | 52 | 53 | 54 | 55 | 56 | Central Portal Snapshots 57 | central-portal-snapshots 58 | https://central.sonatype.com/repository/maven-snapshots/ 59 | 60 | false 61 | 62 | 63 | true 64 | 65 | 66 | 67 | spring-milestones 68 | Spring Milestones 69 | https://repo.spring.io/milestone 70 | 71 | false 72 | 73 | 74 | 75 | spring-snapshots 76 | Spring Snapshots 77 | https://repo.spring.io/snapshot 78 | 79 | false 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/AccountApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.business; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; 9 | 10 | @SpringBootApplication 11 | public class AccountApplication { 12 | 13 | private static final Logger LOG = LoggerFactory.getLogger(AccountApplication.class); 14 | 15 | public static void main(String[] args) { 16 | LOG.info( 17 | "Application profile from system property is [{}]", 18 | System.getProperty("spring.profiles.active")); 19 | new SpringApplication(AccountApplication.class).run(args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/controller/AccountController.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.controller; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Account; 4 | import com.microsoft.openai.samples.assistant.business.models.PaymentMethod; 5 | import com.microsoft.openai.samples.assistant.business.models.Beneficiary; 6 | import com.microsoft.openai.samples.assistant.business.service.AccountService; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import java.util.List; 15 | 16 | @RestController 17 | @RequestMapping("/accounts") 18 | public class AccountController { 19 | 20 | private final AccountService accountService; 21 | private static final Logger logger = LoggerFactory.getLogger(AccountController.class); 22 | 23 | public AccountController(AccountService accountService) { 24 | this.accountService = accountService; 25 | } 26 | 27 | @GetMapping("/{accountId}") 28 | public Account getAccountDetails(@PathVariable String accountId) { 29 | logger.info("Received request to get account details for account id: {}", accountId); 30 | return accountService.getAccountDetails(accountId); 31 | } 32 | 33 | @GetMapping("/{accountId}/paymentmethods/{methodId}") 34 | public PaymentMethod getPaymentMethodDetails(@PathVariable String accountId, @PathVariable String methodId) { 35 | logger.info("Received request to get payment method details for account id: {} and method id: {}", accountId, methodId); 36 | return accountService.getPaymentMethodDetails(methodId); 37 | } 38 | 39 | @GetMapping("/{accountId}/registeredBeneficiaries") 40 | public List getBeneficiaryDetails(@PathVariable String accountId) { 41 | logger.info("Received request to get beneficiary details for account id: {}", accountId); 42 | return accountService.getRegisteredBeneficiary(accountId); 43 | } 44 | } -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.controller; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Account; 4 | import com.microsoft.openai.samples.assistant.business.service.UserService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import java.util.List; 14 | 15 | @RestController 16 | @RequestMapping("/users") 17 | public class UserController { 18 | 19 | private final UserService userService; 20 | private static final Logger logger = LoggerFactory.getLogger(UserController.class); 21 | 22 | 23 | @Autowired 24 | public UserController(UserService userService) { 25 | this.userService = userService; 26 | } 27 | @GetMapping("/{userName}/accounts") 28 | public List getAccountsByUserName(@PathVariable String userName) { 29 | // Implement the logic to get the list of all accounts for a specific user 30 | logger.info("Received request to get accounts for user: {}", userName); 31 | return userService.getAccountsByUserName(userName); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/config/MCPServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.config; 2 | 3 | 4 | import com.microsoft.openai.samples.assistant.business.mcp.server.AccountMCPService; 5 | import com.microsoft.openai.samples.assistant.business.mcp.server.UserMCPService; 6 | import org.springframework.ai.tool.ToolCallbackProvider; 7 | import org.springframework.ai.tool.method.MethodToolCallbackProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class MCPServerConfiguration { 13 | 14 | @Bean 15 | public ToolCallbackProvider accountTools(AccountMCPService accountMCPService) { 16 | return MethodToolCallbackProvider.builder().toolObjects(accountMCPService).build(); 17 | } 18 | 19 | @Bean 20 | public ToolCallbackProvider userTools(UserMCPService userMCPService) { 21 | return MethodToolCallbackProvider.builder().toolObjects(userMCPService).build(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/server/AccountMCPService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.server; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Account; 4 | import com.microsoft.openai.samples.assistant.business.models.Beneficiary; 5 | import com.microsoft.openai.samples.assistant.business.models.PaymentMethod; 6 | import com.microsoft.openai.samples.assistant.business.service.AccountService; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.ai.tool.annotation.Tool; 9 | 10 | import java.util.List; 11 | 12 | @Service 13 | public class AccountMCPService { 14 | 15 | private final AccountService accountService; 16 | public AccountMCPService(AccountService accountService) { 17 | this.accountService = accountService; 18 | } 19 | 20 | @Tool(description = "Get account details and available payment methods") 21 | public Account getAccountDetails(String accountId) { 22 | return this.accountService.getAccountDetails(accountId); 23 | 24 | } 25 | 26 | @Tool(description = "Get payment method detail with available balance") 27 | public PaymentMethod getPaymentMethodDetails(String paymentMethodId) { 28 | return this.accountService.getPaymentMethodDetails(paymentMethodId); 29 | } 30 | 31 | @Tool(description = "Get list of registered beneficiaries for a specific account") 32 | public List getRegisteredBeneficiary(String accountId) { 33 | return this.accountService.getRegisteredBeneficiary(accountId); 34 | } 35 | } -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/server/UserMCPService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.server; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Account; 4 | import com.microsoft.openai.samples.assistant.business.service.UserService; 5 | import org.springframework.ai.tool.annotation.Tool; 6 | import org.springframework.ai.tool.annotation.ToolParam; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | 15 | @Service 16 | public class UserMCPService { 17 | private final UserService userService; 18 | 19 | public UserMCPService(UserService userService) { 20 | this.userService = userService; 21 | } 22 | 23 | @Tool(description = "Get the list of all accounts for a specific user") 24 | public List getAccountsByUserName(@ToolParam( description ="userName once the user has logged" ) String userName) { 25 | return userService.getAccountsByUserName(userName); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/models/Account.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | 8 | import java.util.List; 9 | 10 | @JsonInclude(JsonInclude.Include.NON_NULL) 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public record Account( 13 | @JsonProperty("id") String id, 14 | @JsonProperty("userName") String userName, 15 | @JsonProperty("accountHolderFullName") String accountHolderFullName, 16 | @JsonProperty("currency") String currency, 17 | @JsonProperty("activationDate") String activationDate, 18 | @JsonProperty("balance") String balance, 19 | List paymentMethods 20 | ) {} 21 | 22 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/models/Beneficiary.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | 8 | @JsonIgnoreProperties(ignoreUnknown = true) 9 | public record Beneficiary( 10 | @JsonProperty("id") String id, 11 | @JsonProperty("fullName") String fullName, 12 | @JsonProperty("bankCode") String bankCode, 13 | @JsonProperty("bankName") String bankName 14 | ) {} 15 | 16 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/models/PaymentMethod.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonInclude; 6 | import com.fasterxml.jackson.annotation.JsonProperty; 7 | 8 | @JsonInclude(JsonInclude.Include.NON_NULL) 9 | @JsonIgnoreProperties(ignoreUnknown = true) 10 | public record PaymentMethod( 11 | @JsonProperty("id") String id, 12 | @JsonProperty("type") String type, 13 | @JsonProperty("activationDate") String activationDate, 14 | @JsonProperty("expirationDate") String expirationDate, 15 | @JsonProperty("availableBalance") String availableBalance, 16 | // card number is valued only for credit card type 17 | @JsonProperty("cardNumber") String cardNumber 18 | ) {} 19 | 20 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/models/PaymentMethodSummary.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | 6 | @JsonIgnoreProperties(ignoreUnknown = true) 7 | public record PaymentMethodSummary( 8 | @JsonProperty("id") String id, 9 | @JsonProperty("type") String type, 10 | @JsonProperty("activationDate") String activationDate, 11 | @JsonProperty("expirationDate") String expirationDate 12 | ) {} 13 | 14 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/java/com/microsoft/openai/samples/assistant/business/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.service; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Account; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.*; 7 | 8 | 9 | @Service 10 | public class UserService { 11 | 12 | 13 | private Map accounts = new HashMap<>(); 14 | 15 | public UserService() { 16 | accounts.put( 17 | "alice.user@contoso.com", 18 | new Account( 19 | "1000", 20 | "alice.user@contoso.com", 21 | "Alice User", 22 | "USD", 23 | "2022-01-01", 24 | "5000", 25 | null 26 | ) 27 | ); 28 | accounts.put( 29 | "bob.user@contoso.com", 30 | new Account( 31 | "1010", 32 | "bob.user@contoso.com", 33 | "Bob User", 34 | "EUR", 35 | "2022-01-01", 36 | "10000", 37 | null 38 | ) 39 | ); 40 | accounts.put( 41 | "charlie.user@contoso.com", 42 | new Account( 43 | "1020", 44 | "charlie.user@contoso.com", 45 | "Charlie User", 46 | "EUR", 47 | "2022-01-01", 48 | "3000", 49 | null 50 | ) 51 | ); 52 | 53 | } 54 | public List getAccountsByUserName(String userName) { 55 | return Arrays.asList(accounts.get(userName)); 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/business-api/account/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8070 -------------------------------------------------------------------------------- /app/business-api/account/src/test/java/org/springframework/ai/mcp/sample/client/AccountMCPClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 - 2024 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.ai.mcp.sample.client; 17 | 18 | import java.util.Map; 19 | 20 | import io.modelcontextprotocol.client.McpClient; 21 | import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport; 22 | import io.modelcontextprotocol.spec.McpClientTransport; 23 | import io.modelcontextprotocol.spec.McpSchema.CallToolRequest; 24 | import io.modelcontextprotocol.spec.McpSchema.CallToolResult; 25 | import io.modelcontextprotocol.spec.McpSchema.ListToolsResult; 26 | 27 | /** 28 | * @author Christian Tzolov 29 | */ 30 | 31 | public class AccountMCPClient { 32 | 33 | 34 | 35 | public static void main(String[] args) { 36 | var transport = new HttpClientSseClientTransport("http://localhost:8070"); 37 | 38 | var client = McpClient.sync(transport).build(); 39 | 40 | client.initialize(); 41 | 42 | client.ping(); 43 | 44 | // List and demonstrate tools 45 | ListToolsResult toolsList = client.listTools(); 46 | System.out.println("Available Tools = " + toolsList); 47 | toolsList.tools().stream().forEach(tool -> { 48 | System.out.println("Tool: " + tool.name() + ", description: " + tool.description() + ", schema: " + tool.inputSchema()); 49 | }); 50 | 51 | CallToolResult accountResult = client.callTool(new CallToolRequest("getAccountDetails", 52 | Map.of("accountId", "1010"))); 53 | System.out.println("Account : " + accountResult); 54 | 55 | CallToolResult userResult = client.callTool(new CallToolRequest("getAccountsByUserName", 56 | Map.of("userName", "bob.user@contoso.com"))); 57 | System.out.println("Account for Bob : " + userResult); 58 | 59 | client.closeGracefully(); 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/business-api/payment/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip 20 | -------------------------------------------------------------------------------- /app/business-api/payment/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build 2 | 3 | WORKDIR /workspace/app 4 | EXPOSE 3100 5 | 6 | COPY mvnw . 7 | COPY .mvn .mvn 8 | COPY pom.xml . 9 | COPY src src 10 | 11 | RUN chmod +x ./mvnw 12 | # Convert CRLF to LF 13 | RUN sed -i 's/\r$//' ./mvnw 14 | RUN ./mvnw package -DskipTests 15 | RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) 16 | 17 | RUN apt-get update && apt-get install -y curl 18 | RUN curl -LJ -o applicationinsights-agent-3.5.4.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.5.4/applicationinsights-agent-3.5.4.jar 19 | COPY applicationinsights.json . 20 | 21 | #for production deployment use mcr.microsoft.com/openjdk/jdk:17-distroless 22 | FROM mcr.microsoft.com/openjdk/jdk:17-distroless 23 | 24 | ARG DEPENDENCY=/workspace/app/target/dependency 25 | COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib 26 | COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF 27 | COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app 28 | COPY --from=build /workspace/app/applicationinsights-agent-3.5.4.jar /app 29 | COPY --from=build /workspace/app/applicationinsights.json /app 30 | 31 | EXPOSE 8080 32 | 33 | ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.5.4.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.assistant.business.PaymentApplication"] -------------------------------------------------------------------------------- /app/business-api/payment/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "role": { 3 | "name": "payments-api" 4 | } 5 | } -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/PaymentApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.business; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | @SpringBootApplication 10 | public class PaymentApplication { 11 | 12 | private static final Logger LOG = LoggerFactory.getLogger(PaymentApplication.class); 13 | 14 | public static void main(String[] args) { 15 | LOG.info( 16 | "Application profile from system property is [{}]", 17 | System.getProperty("spring.profiles.active")); 18 | new SpringApplication(PaymentApplication.class).run(args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/controller/PaymentsController.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.controller; 2 | 3 | import com.microsoft.openai.samples.assistant.business.models.Payment; 4 | import com.microsoft.openai.samples.assistant.business.service.PaymentService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | public class PaymentsController { 14 | 15 | private static final Logger logger = LoggerFactory.getLogger(PaymentsController.class); 16 | 17 | private final PaymentService paymentService; 18 | 19 | public PaymentsController(PaymentService paymentService) { 20 | this.paymentService = paymentService; 21 | } 22 | 23 | @PostMapping("/payments") 24 | public void submitPayment(@RequestBody Payment payment) { 25 | logger.info("Received payment request: {}", payment); 26 | paymentService.processPayment(payment); 27 | } 28 | } -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/config/MCPServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.config; 2 | 3 | import com.microsoft.openai.samples.assistant.business.mcp.server.PaymentMCPService; 4 | import org.springframework.ai.tool.ToolCallbackProvider; 5 | import org.springframework.ai.tool.method.MethodToolCallbackProvider; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class MCPServerConfiguration { 11 | 12 | @Bean 13 | public ToolCallbackProvider paymentTools(PaymentMCPService paymentMCPService) { 14 | return MethodToolCallbackProvider.builder().toolObjects(paymentMCPService).build(); 15 | } 16 | } -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/server/PaymentMCPService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.server; 2 | 3 | 4 | import com.microsoft.openai.samples.assistant.business.models.Payment; 5 | import com.microsoft.openai.samples.assistant.business.service.PaymentService; 6 | import org.springframework.ai.tool.annotation.Tool; 7 | 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class PaymentMCPService { 12 | 13 | private final PaymentService paymentService; 14 | 15 | public PaymentMCPService(PaymentService paymentService) { 16 | this.paymentService = paymentService; 17 | } 18 | 19 | @Tool(description = "Submit a payment request") 20 | public void processPayment(Payment payment){ 21 | paymentService.processPayment(payment); 22 | } 23 | } -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/models/Payment.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public record Payment( 9 | @JsonProperty("description") String description, 10 | @JsonProperty("recipientName") String recipientName, 11 | @JsonProperty("recipientBankCode") String recipientBankCode, 12 | @JsonProperty("accountId") String accountId, 13 | @JsonProperty("paymentMethodId") String paymentMethodId, 14 | @JsonProperty("paymentType") String paymentType, 15 | @JsonProperty("amount") String amount, 16 | @JsonProperty("timestamp") String timestamp 17 | ) {} -------------------------------------------------------------------------------- /app/business-api/payment/src/main/java/com/microsoft/openai/samples/assistant/business/models/Transaction.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.models; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public record Transaction( 9 | @JsonProperty("id") String id, 10 | @JsonProperty("description") String description, 11 | //income/outcome 12 | @JsonProperty("type") String type, 13 | @JsonProperty("recipientName") String recipientName, 14 | @JsonProperty("recipientBankReference") String recipientBankReference, 15 | @JsonProperty("accountId") String accountId, 16 | @JsonProperty("paymentType") String paymentType, 17 | @JsonProperty("amount") String amount, 18 | @JsonProperty("timestamp") String timestamp 19 | ) {} -------------------------------------------------------------------------------- /app/business-api/payment/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8060 2 | 3 | logging.level.org.springframework.web=DEBUG -------------------------------------------------------------------------------- /app/business-api/payment/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | transactions.api.url=${TRANSACTIONS_API_SERVER_URL} -------------------------------------------------------------------------------- /app/business-api/payment/src/main/resources/payments.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | info: 3 | title: Payment API 4 | version: 1.0.0 5 | paths: 6 | /payments: 7 | post: 8 | operationId: submitPayment 9 | summary: Submit a payment request 10 | requestBody: 11 | required: true 12 | content: 13 | application/json: 14 | schema: 15 | $ref: '#/components/schemas/Payment' 16 | responses: 17 | '201': 18 | description: Payment request submitted successfully 19 | '400': 20 | description: Invalid request body 21 | '500': 22 | description: Internal server error 23 | components: 24 | schemas: 25 | Payment: 26 | type: object 27 | properties: 28 | description: 29 | type: string 30 | description: Description of the payment 31 | recipientName: 32 | type: string 33 | description: Name of the recipient 34 | recipientId: 35 | type: string 36 | description: ID of the recipient 37 | recipientBankCode: 38 | type: string 39 | description: Bank code of the recipient 40 | accountId: 41 | type: string 42 | description: ID of the account 43 | paymentMethodId: 44 | type: string 45 | description: ID of the payment method 46 | amount: 47 | type: string 48 | description: Amount of the payment 49 | timestamp: 50 | type: string 51 | description: Timestamp of the payment 52 | required: 53 | - description 54 | - recipientName 55 | - recipientBankCode 56 | - accountId 57 | - paymentMethodId 58 | - amount 59 | - timestamp -------------------------------------------------------------------------------- /app/business-api/transactions-history/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip 20 | -------------------------------------------------------------------------------- /app/business-api/transactions-history/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build 2 | 3 | WORKDIR /workspace/app 4 | EXPOSE 3100 5 | 6 | COPY mvnw . 7 | COPY .mvn .mvn 8 | COPY pom.xml . 9 | COPY src src 10 | 11 | RUN chmod +x ./mvnw 12 | # Convert CRLF to LF 13 | RUN sed -i 's/\r$//' ./mvnw 14 | RUN ./mvnw package -DskipTests 15 | RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar) 16 | 17 | #install curl 18 | RUN apt-get update && apt-get install -y curl 19 | RUN curl -LJ -o applicationinsights-agent-3.5.4.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.5.4/applicationinsights-agent-3.5.4.jar 20 | COPY applicationinsights.json . 21 | 22 | #for production deployment use mcr.microsoft.com/openjdk/jdk:17-distroless 23 | FROM mcr.microsoft.com/openjdk/jdk:17-distroless 24 | 25 | ARG DEPENDENCY=/workspace/app/target/dependency 26 | COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib 27 | COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF 28 | COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app 29 | COPY --from=build /workspace/app/applicationinsights-agent-3.5.4.jar /app 30 | COPY --from=build /workspace/app/applicationinsights.json /app 31 | 32 | EXPOSE 8080 33 | 34 | ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.5.4.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.assistant.business.TransactionsHistoryApplication"] -------------------------------------------------------------------------------- /app/business-api/transactions-history/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "role": { 3 | "name": "transactions-api" 4 | } 5 | } -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/java/com/microsoft/openai/samples/assistant/business/Transaction.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public record Transaction( 9 | @JsonProperty("id") String id, 10 | @JsonProperty("description") String description, 11 | //income/outcome 12 | @JsonProperty("type") String type, 13 | @JsonProperty("recipientName") String recipientName, 14 | @JsonProperty("recipientBankReference") String recipientBankReference, 15 | @JsonProperty("accountId") String accountId, 16 | @JsonProperty("paymentType") String paymentType, 17 | @JsonProperty("amount") String amount, 18 | @JsonProperty("timestamp") String timestamp 19 | ) {} -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/java/com/microsoft/openai/samples/assistant/business/TransactionController.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.web.bind.annotation.*; 6 | 7 | import java.util.List; 8 | 9 | @RestController 10 | @RequestMapping("/transactions") 11 | public class TransactionController { 12 | 13 | private final TransactionService transactionService; 14 | private static final Logger logger = LoggerFactory.getLogger(TransactionController.class); 15 | public TransactionController(TransactionService transactionService) { 16 | this.transactionService = transactionService; 17 | } 18 | 19 | @GetMapping("/{accountId}") 20 | public List getTransactions(@PathVariable String accountId, @RequestParam(name = "recipient_name", required = false) String recipientName){ 21 | logger.info("Received request to get transactions for accountid[{}]. Recipient filter is[{}]",accountId,recipientName); 22 | if(recipientName != null && !recipientName.isEmpty()){ 23 | return transactionService.getTransactionsByRecipientName(accountId, recipientName); 24 | } 25 | else 26 | return transactionService.getlastTransactions(accountId); 27 | } 28 | 29 | @PostMapping("/{accountId}") 30 | public void notifyTransaction(@PathVariable String accountId, @RequestBody Transaction transaction){ 31 | logger.info("Received request to notify transaction for accountid[{}]. {}", accountId,transaction); 32 | transactionService.notifyTransaction(accountId, transaction); 33 | } 34 | 35 | 36 | } -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/java/com/microsoft/openai/samples/assistant/business/TransactionsHistoryApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.business; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | 9 | @SpringBootApplication 10 | public class TransactionsHistoryApplication { 11 | 12 | private static final Logger LOG = LoggerFactory.getLogger(TransactionsHistoryApplication.class); 13 | 14 | public static void main(String[] args) { 15 | LOG.info( 16 | "Application profile from system property is [{}]", 17 | System.getProperty("spring.profiles.active")); 18 | new SpringApplication(TransactionsHistoryApplication.class).run(args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/config/MCPServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.config; 2 | 3 | import com.microsoft.openai.samples.assistant.business.mcp.server.TransactionMCPService; 4 | import org.springframework.ai.tool.ToolCallbackProvider; 5 | import org.springframework.ai.tool.method.MethodToolCallbackProvider; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class MCPServerConfiguration { 11 | 12 | @Bean 13 | public ToolCallbackProvider transactionTools(TransactionMCPService transactionMCPService) { 14 | return MethodToolCallbackProvider.builder().toolObjects(transactionMCPService).build(); 15 | } 16 | } -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/java/com/microsoft/openai/samples/assistant/business/mcp/server/TransactionMCPService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.business.mcp.server; 2 | 3 | import com.microsoft.openai.samples.assistant.business.Transaction; 4 | import com.microsoft.openai.samples.assistant.business.TransactionService; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.ai.tool.annotation.Tool; 7 | import org.springframework.ai.tool.annotation.ToolParam; 8 | 9 | import java.util.List; 10 | 11 | @Service 12 | public class TransactionMCPService { 13 | 14 | private final TransactionService transactionService; 15 | 16 | public TransactionMCPService(TransactionService transactionService) { 17 | this.transactionService = transactionService; 18 | } 19 | 20 | @Tool(description = "Get transactions by recipient name") 21 | public List getTransactionsByRecipientName( 22 | @ToolParam(description = "The account ID") String accountId, 23 | @ToolParam(description = "The recipient's name") String recipientName) { 24 | return transactionService.getTransactionsByRecipientName(accountId, recipientName); 25 | } 26 | 27 | @Tool(description = "Get the last transactions for an account") 28 | public List getLastTransactions( 29 | @ToolParam(description = "The account ID") String accountId) { 30 | return transactionService.getlastTransactions(accountId); 31 | } 32 | } -------------------------------------------------------------------------------- /app/business-api/transactions-history/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=8090 2 | 3 | logging.level.org.springframework.web=DEBUG -------------------------------------------------------------------------------- /app/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | frontend: 3 | image: agent-openai-java-banking-assistant/frontend 4 | build: ./frontend 5 | environment: 6 | REACT_APP_API_BASE_URL: "http://copilot:8080" 7 | ports: 8 | - "80:80" 9 | copilot: 10 | image: agent-openai-java-banking-assistant/copilot-backend 11 | build: ./copilot 12 | environment: 13 | - AZURE_STORAGE_ACCOUNT=${AZURE_STORAGE_ACCOUNT} 14 | - AZURE_STORAGE_CONTAINER=${AZURE_STORAGE_CONTAINER} 15 | - AZURE_OPENAI_CHATGPT_MODEL=${AZURE_OPENAI_CHATGPT_MODEL} 16 | - AZURE_OPENAI_SERVICE=${AZURE_OPENAI_SERVICE} 17 | - AZURE_OPENAI_CHATGPT_DEPLOYMENT=${AZURE_OPENAI_CHATGPT_DEPLOYMENT} 18 | - AZURE_DOCUMENT_INTELLIGENCE_SERVICE=${AZURE_DOCUMENT_INTELLIGENCE_SERVICE} 19 | - spring_profiles_active=docker 20 | - ACCOUNTS_API_SERVER_URL=http://account:8080 21 | - PAYMENTS_API_SERVER_URL=http://payment:8080 22 | - TRANSACTIONS_API_SERVER_URL=http://transaction:8080 23 | - AZURE_CLIENT_ID=${servicePrincipal} 24 | - AZURE_CLIENT_SECRET=${servicePrincipalPassword} 25 | - AZURE_TENANT_ID=${servicePrincipalTenant} 26 | account: 27 | image: agent-openai-java-banking-assistant/business-account 28 | build: 29 | context: ./business-api/account 30 | payment: 31 | image: agent-openai-java-banking-assistant/business-payment 32 | build: 33 | context: ./business-api/payment 34 | environment: 35 | - TRANSACTIONS_API_SERVER_URL=http://transaction:8080 36 | transaction: 37 | image: agent-openai-java-banking-assistant/business-transaction-history 38 | build: 39 | context: ./business-api/transactions-history 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/copilot/.mvn/jvm.config: -------------------------------------------------------------------------------- 1 | --add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED 2 | --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED 3 | --add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED 4 | --add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED 5 | -------------------------------------------------------------------------------- /app/copilot/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | wrapperVersion=3.3.2 18 | distributionType=only-script 19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip 20 | -------------------------------------------------------------------------------- /app/copilot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build 2 | 3 | WORKDIR /workspace/app 4 | EXPOSE 3100 5 | 6 | COPY mvnw . 7 | COPY .mvn .mvn 8 | COPY pom.xml . 9 | COPY copilot-backend copilot-backend 10 | COPY copilot-common copilot-common 11 | COPY langchain4j-agents langchain4j-agents 12 | 13 | RUN chmod +x ./mvnw 14 | # Convert CRLF to LF 15 | RUN sed -i 's/\r$//' ./mvnw 16 | RUN ./mvnw package -DskipTests 17 | RUN mkdir -p copilot-backend/target/dependency && (cd copilot-backend/target/dependency; jar -xf ../*.jar) 18 | 19 | #install curl 20 | RUN apt-get update && apt-get install -y curl 21 | RUN curl -LJ -o applicationinsights-agent-3.5.4.jar https://github.com/microsoft/ApplicationInsights-Java/releases/download/3.5.4/applicationinsights-agent-3.5.4.jar 22 | COPY applicationinsights.json . 23 | 24 | #for production deployment use mcr.microsoft.com/openjdk/jdk:17-distroless 25 | FROM mcr.microsoft.com/openjdk/jdk:17-distroless 26 | 27 | ARG DEPENDENCY=/workspace/app/copilot-backend/target/dependency/ 28 | COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib 29 | COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF 30 | COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app 31 | COPY --from=build /workspace/app/applicationinsights-agent-3.5.4.jar /app 32 | COPY --from=build /workspace/app/applicationinsights.json /app 33 | EXPOSE 8080 34 | 35 | ENTRYPOINT ["java","-javaagent:/app/applicationinsights-agent-3.5.4.jar","-noverify", "-XX:MaxRAMPercentage=70", "-XX:+UseParallelGC", "-XX:ActiveProcessorCount=2", "-cp","app:app/lib/*","com.microsoft.openai.samples.assistant.CopilotApplication"] -------------------------------------------------------------------------------- /app/copilot/applicationinsights.json: -------------------------------------------------------------------------------- 1 | { 2 | "role": { 3 | "name": "copilot-api" 4 | } 5 | } -------------------------------------------------------------------------------- /app/copilot/copilot-backend/manifests/azd-env-configmap.yml: -------------------------------------------------------------------------------- 1 | # Updated 2024-04-18 16:01:23 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: azd-env-configmap 6 | data: 7 | API_ALLOW_ORIGINS: "" 8 | APPLICATIONINSIGHTS_CONNECTION_STRING: "InstrumentationKey=6fa478c2-3ea8-451e-8350-acafdaf6264a;IngestionEndpoint=https://francecentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://francecentral.livediagnostics.monitor.azure.com/;ApplicationId=cc2958e9-c1f3-4fc8-910f-49d81979c208" 9 | AZURE_AKS_CLUSTER_NAME: "aks-yvh3rjtnvwvvm" 10 | AZURE_CLIENT_ID: "19ccc9b6-37b0-47ce-b99e-efddf02bef26" 11 | AZURE_CONTAINER_REGISTRY_ENDPOINT: "cryvh3rjtnvwvvm.azurecr.io" 12 | AZURE_CONTAINER_REGISTRY_NAME: "cryvh3rjtnvwvvm" 13 | AZURE_ENV_NAME: "java-chat-12-aks-test" 14 | AZURE_FORMRECOGNIZER_RESOURCE_GROUP: "rg-java-chat-12-aks-test" 15 | AZURE_FORMRECOGNIZER_SERVICE: "cog-fr-yvh3rjtnvwvvm" 16 | AZURE_KEY_VAULT_ENDPOINT: "https://kv-yvh3rjtnvwvvm.vault.azure.net/" 17 | AZURE_LOCATION: "francecentral" 18 | AZURE_OPENAI_CHATGPT_DEPLOYMENT: "chat" 19 | AZURE_OPENAI_CHATGPT_MODEL: "gpt-35-turbo" 20 | AZURE_OPENAI_EMB_DEPLOYMENT: "embedding" 21 | AZURE_OPENAI_EMB_MODEL_NAME: "text-embedding-ada-002" 22 | AZURE_OPENAI_RESOURCE_GROUP: "rg-java-chat-12-aks-test" 23 | AZURE_OPENAI_SERVICE: "cog-yvh3rjtnvwvvm" 24 | AZURE_RESOURCE_GROUP: "rg-java-chat-12-aks-test" 25 | AZURE_SEARCH_INDEX: "gptkbindex" 26 | AZURE_SEARCH_SERVICE: "gptkb-yvh3rjtnvwvvm" 27 | AZURE_SEARCH_SERVICE_RESOURCE_GROUP: "rg-java-chat-12-aks-test" 28 | AZURE_SERVICEBUS_NAMESPACE: "sb-yvh3rjtnvwvvm" 29 | AZURE_SERVICEBUS_SKU_NAME: "Standard" 30 | AZURE_STORAGE_ACCOUNT: "styvh3rjtnvwvvm" 31 | AZURE_STORAGE_CONTAINER: "content" 32 | AZURE_STORAGE_RESOURCE_GROUP: "rg-java-chat-12-aks-test" 33 | AZURE_SUBSCRIPTION_ID: "8b82fc4d-aabe-4658-88f2-5674bf49eec0" 34 | AZURE_TENANT_ID: "fa3408a7-4997-49b5-bda2-62886815fa49" 35 | OPENAI_API_KEY: "" 36 | OPENAI_HOST: "azure" 37 | OPENAI_ORGANIZATION: "" 38 | REACT_APP_APPLICATIONINSIGHTS_CONNECTION_STRING: "InstrumentationKey=6fa478c2-3ea8-451e-8350-acafdaf6264a;IngestionEndpoint=https://francecentral-1.in.applicationinsights.azure.com/;LiveEndpoint=https://francecentral.livediagnostics.monitor.azure.com/;ApplicationId=cc2958e9-c1f3-4fc8-910f-49d81979c208" 39 | SERVICE_API_ENDPOINT_URL: "http://68.220.199.26" 40 | SERVICE_API_IMAGE_NAME: "crnq6gqbtyxqno2.azurecr.io/azure-search-openai-demo/api-java-chat-12-aks-test:azd-deploy-1710941647" 41 | SERVICE_FRONTEND_ENDPOINT_URL: "http://10.0.118.173:80" 42 | SERVICE_FRONTEND_IMAGE_NAME: "crnq6gqbtyxqno2.azurecr.io/azure-search-openai-demo/frontend-java-chat-12-aks-test:azd-deploy-1710941650" 43 | SERVICE_INDEXER_ENDPOINT_URL: "http://10.0.165.214:80" 44 | SERVICE_INDEXER_IMAGE_NAME: "crnq6gqbtyxqno2.azurecr.io/azure-search-openai-demo/indexer-java-chat-12-aks-test:azd-deploy-1710941756" 45 | 46 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/manifests/backend-deployment.tmpl.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: backend-deployment 5 | namespace: azure-open-ai 6 | labels: 7 | app: backend 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: backend 13 | template: 14 | metadata: 15 | labels: 16 | app: backend 17 | spec: 18 | containers: 19 | - name: backend 20 | image: {{.Env.SERVICE_API_IMAGE_NAME}} 21 | imagePullPolicy: IfNotPresent 22 | ports: 23 | - containerPort: 8080 24 | envFrom: 25 | - configMapRef: 26 | name: azd-env-configmap 27 | resources: 28 | requests: 29 | memory: "2Gi" 30 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/manifests/backend-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: backend-service 5 | namespace: azure-open-ai 6 | spec: 7 | type: ClusterIP 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 8080 12 | selector: 13 | app: backend 14 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/manifests/ingress.yml: -------------------------------------------------------------------------------- 1 | apiVersion: networking.k8s.io/v1 2 | kind: Ingress 3 | metadata: 4 | name: ingress-api 5 | namespace: azure-open-ai 6 | # annotations: 7 | # nginx.ingress.kubernetes.io/use-regex: "true" 8 | # nginx.ingress.kubernetes.io/rewrite-target: /$2 9 | spec: 10 | ingressClassName: webapprouting.kubernetes.azure.com 11 | rules: 12 | - http: 13 | paths: 14 | - path: /api 15 | pathType: Prefix 16 | backend: 17 | service: 18 | name: backend-service 19 | port: 20 | number: 80 21 | - path: / 22 | pathType: Prefix 23 | backend: 24 | service: 25 | name: frontend-service 26 | port: 27 | number: 80 -------------------------------------------------------------------------------- /app/copilot/copilot-backend/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.3.6 9 | 10 | 11 | com.microsoft.openai.samples.assistant 12 | personal-finance-assistant-copilot 13 | 1.0.0-SNAPSHOT 14 | personal-finance-assistant-copilot-langchain4j 15 | This sample demonstrate how to create a generative ai multi-agent solution for a banking personal assistant 16 | 17 | 18 | 17 19 | 17 20 | 21 | 5.20.0 22 | 4.5.1 23 | 1.0.0-beta2 24 | 25 | 26 | 27 | 28 | 29 | com.azure.spring 30 | spring-cloud-azure-dependencies 31 | ${spring-cloud-azure.version} 32 | pom 33 | import 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | com.microsoft.openai.samples.assistant 42 | langchain4j-agents 43 | 1.0.0-SNAPSHOT 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-web 48 | 49 | 50 | org.springframework.boot 51 | spring-boot-starter-security 52 | 53 | 54 | dev.langchain4j 55 | langchain4j-azure-open-ai 56 | ${langchain4j.version} 57 | 58 | 59 | com.azure 60 | azure-identity 61 | 62 | 63 | 64 | 65 | 66 | 67 | org.springframework.boot 68 | spring-boot-maven-plugin 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/CopilotApplication.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant; 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; 9 | 10 | @SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) 11 | 12 | public class CopilotApplication { 13 | 14 | private static final Logger LOG = LoggerFactory.getLogger(CopilotApplication.class); 15 | 16 | public static void main(String[] args) { 17 | LOG.info( 18 | "Application profile from system property is [{}]", 19 | System.getProperty("spring.profiles.active")); 20 | new SpringApplication(CopilotApplication.class).run(args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/common/ChatGPTMessage.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.common; 3 | 4 | import com.azure.core.util.ExpandableStringEnum; 5 | 6 | import java.util.Collection; 7 | 8 | public record ChatGPTMessage(ChatRole role, String content) { 9 | 10 | public static final class ChatRole extends ExpandableStringEnum { 11 | public static final ChatRole SYSTEM = fromString("system"); 12 | 13 | public static final ChatRole ASSISTANT = fromString("assistant"); 14 | 15 | public static final ChatRole USER = fromString("user"); 16 | 17 | public static ChatRole fromString(String name) { 18 | return fromString(name, ChatRole.class); 19 | } 20 | 21 | public static Collection values() { 22 | return values(ChatRole.class); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/AzureAuthenticationConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | import com.azure.core.credential.TokenCredential; 5 | import com.azure.identity.AzureCliCredentialBuilder; 6 | import com.azure.identity.EnvironmentCredentialBuilder; 7 | import com.azure.identity.ManagedIdentityCredentialBuilder; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Profile; 12 | 13 | @Configuration 14 | public class AzureAuthenticationConfiguration { 15 | 16 | @Value("${azure.identity.client-id}") 17 | String clientId; 18 | 19 | @Profile("dev") 20 | @Bean 21 | public TokenCredential localTokenCredential() { 22 | return new AzureCliCredentialBuilder().build(); 23 | } 24 | 25 | @Profile("docker") 26 | @Bean 27 | public TokenCredential servicePrincipalTokenCredential() { 28 | return new EnvironmentCredentialBuilder().build(); 29 | } 30 | 31 | @Bean 32 | @Profile("default") 33 | public TokenCredential managedIdentityTokenCredential() { 34 | if (this.clientId.equals("system-managed-identity")) 35 | return new ManagedIdentityCredentialBuilder().build(); 36 | else 37 | return new ManagedIdentityCredentialBuilder().clientId(this.clientId).build(); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/BlobStorageProxyConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | import com.azure.ai.documentintelligence.DocumentIntelligenceClient; 5 | import com.azure.core.credential.TokenCredential; 6 | import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; 7 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.AccountMCPAgent; 8 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.PaymentMCPAgent; 9 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.TransactionHistoryMCPAgent; 10 | import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; 11 | import com.microsoft.openai.samples.assistant.security.LoggedUserService; 12 | import dev.langchain4j.model.chat.ChatLanguageModel; 13 | import org.springframework.beans.factory.annotation.Value; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.annotation.Configuration; 16 | 17 | @Configuration 18 | public class BlobStorageProxyConfiguration { 19 | @Value("${storage-account.service}") 20 | String storageAccountServiceName; 21 | @Value("${blob.container.name}") 22 | String containerName; 23 | 24 | @Bean 25 | public BlobStorageProxy blobStorageProxy(TokenCredential tokenCredential) { 26 | return new BlobStorageProxy(storageAccountServiceName,containerName,tokenCredential); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/DocumentIntelligenceConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | import com.azure.ai.documentintelligence.DocumentIntelligenceClient; 5 | import com.azure.ai.documentintelligence.DocumentIntelligenceClientBuilder; 6 | import com.azure.core.credential.TokenCredential; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class DocumentIntelligenceConfiguration { 13 | 14 | @Value("${documentintelligence.service}") 15 | String documentIntelligenceServiceName; 16 | 17 | final TokenCredential tokenCredential; 18 | 19 | public DocumentIntelligenceConfiguration(TokenCredential tokenCredential) { 20 | this.tokenCredential = tokenCredential; 21 | } 22 | 23 | @Bean 24 | public DocumentIntelligenceClient documentIntelligenceClient() { 25 | String endpoint = "https://%s.cognitiveservices.azure.com".formatted(documentIntelligenceServiceName); 26 | 27 | return new DocumentIntelligenceClientBuilder() 28 | .credential(tokenCredential) 29 | .endpoint(endpoint) 30 | .buildClient(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/DocumentIntelligenceInvoiceScanConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | import com.azure.ai.documentintelligence.DocumentIntelligenceClient; 5 | import com.azure.ai.documentintelligence.DocumentIntelligenceClientBuilder; 6 | import com.azure.core.credential.TokenCredential; 7 | import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; 8 | import com.microsoft.openai.samples.assistant.proxy.BlobStorageProxy; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | @Configuration 14 | public class DocumentIntelligenceInvoiceScanConfiguration { 15 | 16 | @Value("${documentintelligence.service}") 17 | String documentIntelligenceServiceName; 18 | 19 | final TokenCredential tokenCredential; 20 | 21 | public DocumentIntelligenceInvoiceScanConfiguration(TokenCredential tokenCredential) { 22 | this.tokenCredential = tokenCredential; 23 | } 24 | 25 | @Bean 26 | public DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper(BlobStorageProxy blobStorageProxy) { 27 | 28 | String endpoint = "https://%s.cognitiveservices.azure.com".formatted(documentIntelligenceServiceName); 29 | 30 | var documentIntelligenceClient = new DocumentIntelligenceClientBuilder() 31 | .credential(tokenCredential) 32 | .endpoint(endpoint) 33 | .buildClient(); 34 | 35 | return new DocumentIntelligenceInvoiceScanHelper(documentIntelligenceClient,blobStorageProxy); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/Langchain4JConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | 5 | import com.azure.ai.openai.OpenAIClient; 6 | 7 | import dev.langchain4j.model.azure.AzureOpenAiChatModel; 8 | import dev.langchain4j.model.chat.ChatLanguageModel; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | @Configuration 14 | public class Langchain4JConfiguration { 15 | 16 | @Value("${openai.chatgpt.deployment}") 17 | private String gptChatDeploymentModelId; 18 | 19 | @Bean 20 | public ChatLanguageModel chatLanguageModel(OpenAIClient azureOpenAICLient) { 21 | 22 | return AzureOpenAiChatModel.builder() 23 | .openAIClient(azureOpenAICLient) 24 | .deploymentName(gptChatDeploymentModelId) 25 | .temperature(0.3) 26 | .logRequestsAndResponses(true) 27 | .build(); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/config/MCPAgentsConfiguration.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.config; 3 | 4 | import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; 5 | import com.microsoft.openai.samples.assistant.langchain4j.agent.SupervisorAgent; 6 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.AccountMCPAgent; 7 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.PaymentMCPAgent; 8 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.TransactionHistoryMCPAgent; 9 | import com.microsoft.openai.samples.assistant.security.LoggedUserService; 10 | import dev.langchain4j.model.chat.ChatLanguageModel; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.Configuration; 14 | 15 | import java.util.List; 16 | 17 | @Configuration 18 | public class MCPAgentsConfiguration { 19 | @Value("${transactions.api.url}") String transactionsMCPServerUrl; 20 | @Value("${accounts.api.url}") String accountsMCPServerUrl; 21 | @Value("${payments.api.url}") String paymentsMCPServerUrl; 22 | 23 | private final ChatLanguageModel chatLanguageModel; 24 | private final LoggedUserService loggedUserService; 25 | private final DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper; 26 | 27 | public MCPAgentsConfiguration(ChatLanguageModel chatLanguageModel, LoggedUserService loggedUserService, DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper) { 28 | this.chatLanguageModel = chatLanguageModel; 29 | this.loggedUserService = loggedUserService; 30 | this.documentIntelligenceInvoiceScanHelper = documentIntelligenceInvoiceScanHelper; 31 | } 32 | @Bean 33 | public AccountMCPAgent accountMCPAgent() { 34 | return new AccountMCPAgent(chatLanguageModel, loggedUserService.getLoggedUser().username(), accountsMCPServerUrl); 35 | } 36 | 37 | @Bean 38 | public TransactionHistoryMCPAgent transactionHistoryMCPAgent() { 39 | return new TransactionHistoryMCPAgent(chatLanguageModel, loggedUserService.getLoggedUser().username(), transactionsMCPServerUrl,accountsMCPServerUrl); 40 | } 41 | 42 | @Bean 43 | public PaymentMCPAgent paymentMCPAgent() { 44 | return new PaymentMCPAgent(chatLanguageModel,documentIntelligenceInvoiceScanHelper, loggedUserService.getLoggedUser().username(),transactionsMCPServerUrl,accountsMCPServerUrl, paymentsMCPServerUrl); 45 | } 46 | 47 | @Bean 48 | public SupervisorAgent supervisorAgent(ChatLanguageModel chatLanguageModel){ 49 | return new SupervisorAgent(chatLanguageModel, 50 | List.of(accountMCPAgent(), 51 | transactionHistoryMCPAgent(), 52 | paymentMCPAgent())); 53 | 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequest.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | import java.util.List; 5 | 6 | public record ChatAppRequest( 7 | List messages, 8 | 9 | List attachments, 10 | ChatAppRequestContext context, 11 | boolean stream, 12 | String approach) {} 13 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestContext.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | public record ChatAppRequestContext(ChatAppRequestOverrides overrides) {} 5 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatAppRequestOverrides.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | public record ChatAppRequestOverrides( 5 | boolean semantic_ranker, 6 | boolean semantic_captions, 7 | String exclude_category, 8 | int top, 9 | float temperature, 10 | String prompt_template, 11 | String prompt_template_prefix, 12 | String prompt_template_suffix, 13 | boolean suggest_followup_questions, 14 | boolean use_oid_security_filter, 15 | boolean use_groups_security_filter, 16 | String semantic_kernel_mode) {} 17 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ChatResponse.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | 5 | 6 | import com.microsoft.openai.samples.assistant.common.ChatGPTMessage; 7 | import dev.langchain4j.data.message.AiMessage; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public record ChatResponse(List choices) { 13 | 14 | public static ChatResponse buildChatResponse(AiMessage aiMessage) { 15 | List dataPoints = Collections.emptyList(); 16 | String thoughts = ""; 17 | List attachments = Collections.emptyList(); 18 | 19 | return new ChatResponse( 20 | List.of( 21 | new ResponseChoice( 22 | 0, 23 | new ResponseMessage( 24 | aiMessage.text(), 25 | ChatGPTMessage.ChatRole.ASSISTANT.toString(), 26 | attachments 27 | ), 28 | new ResponseContext(thoughts, dataPoints), 29 | new ResponseMessage( 30 | aiMessage.text(), 31 | ChatGPTMessage.ChatRole.ASSISTANT.toString(), 32 | attachments)))); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseChoice.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | public record ResponseChoice( 5 | int index, ResponseMessage message, ResponseContext context, ResponseMessage delta) {} 6 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseContext.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | import java.util.List; 5 | 6 | public record ResponseContext(String thoughts, List data_points) {} 7 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller; 3 | 4 | import java.util.List; 5 | 6 | public record ResponseMessage(String content, String role, List attachments) {} 7 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/controller/auth/AuthSetup.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.controller.auth; 3 | 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.RestController; 6 | 7 | @RestController 8 | public class AuthSetup { 9 | 10 | @GetMapping("/api/auth_setup") 11 | public String authSetup() { 12 | return """ 13 | { 14 | "useLogin": false 15 | } 16 | """ 17 | .stripIndent(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/LoggedUserPlugin.java.sample: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.plugin; 2 | 3 | import com.microsoft.openai.samples.assistant.security.LoggedUser; 4 | import com.microsoft.openai.samples.assistant.security.LoggedUserService; 5 | import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; 6 | 7 | public class LoggedUserPlugin { 8 | 9 | private final LoggedUserService loggedUserService; 10 | public LoggedUserPlugin(LoggedUserService loggedUserService) 11 | { 12 | this.loggedUserService = loggedUserService; 13 | } 14 | @DefineKernelFunction(name = "UserContext", description = "Gets the user details after login") 15 | public String getUserContext() { 16 | LoggedUser loggedUser = loggedUserService.getLoggedUser(); 17 | return loggedUser.toString(); 18 | 19 | 20 | } 21 | 22 | } 23 | 24 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/PaymentMockPlugin.java.sample: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.plugin; 2 | 3 | import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; 4 | import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; 5 | 6 | public class PaymentMockPlugin { 7 | 8 | 9 | @DefineKernelFunction(name = "payBill", description = "Gets the last payment transactions based on the payee, recipient name") 10 | public String submitBillPayment( 11 | @KernelFunctionParameter(name = "recipientName", description = "Name of the payee, recipient") String recipientName, 12 | @KernelFunctionParameter(name = "documentId", description = " the bill id or invoice number") String documentID, 13 | @KernelFunctionParameter(name = "amount", description = "the total amount to pay") String amount) { 14 | 15 | System.out.println("Bill payment executed for recipient: " + recipientName + " with documentId: " + documentID + " and amount: " + amount); 16 | 17 | return "Payment Successful"; 18 | 19 | } 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/TransactionHistoryMockPlugin.java.sample: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.plugin; 2 | 3 | import com.microsoft.openai.samples.assistant.plugin.mock.TransactionServiceMock; 4 | import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; 5 | import com.microsoft.semantickernel.semanticfunctions.annotations.KernelFunctionParameter; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class TransactionHistoryMockPlugin { 10 | private static final Logger LOGGER = LoggerFactory.getLogger(TransactionHistoryMockPlugin.class); 11 | private final TransactionServiceMock transactionService; 12 | public TransactionHistoryMockPlugin(){ 13 | this.transactionService = new TransactionServiceMock(); 14 | } 15 | 16 | @DefineKernelFunction(name = "getTransactionsByRecepient", description = "Gets the last payment transactions based on the payee, recipient name") 17 | public String getTransactionsByRecepient( 18 | @KernelFunctionParameter(name = "accountId", description = "The banking account id of the user") String accountId, 19 | @KernelFunctionParameter(name = "recipientName", description = "Name of the payee, recipient") String recipientName) { 20 | String transactionsByRecipient = transactionService.getTransactionsByRecipientName(accountId,recipientName).toString(); 21 | LOGGER.info("Transactions for [{}]:{} ",recipientName,transactionsByRecipient); 22 | return transactionsByRecipient; 23 | 24 | 25 | } 26 | 27 | 28 | @DefineKernelFunction(name = "getTransactions", description = "Gets the last payment transactions") 29 | public String getTransactions( 30 | @KernelFunctionParameter(name = "accountId", description = "The banking account id of the user") String accountId 31 | ) { 32 | String lastTransactions = transactionService.getlastTransactions(accountId).toString(); 33 | LOGGER.info("Last transactions:{} ",lastTransactions); 34 | return lastTransactions; 35 | 36 | 37 | } 38 | 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/plugin/mock/PaymentTransaction.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.plugin.mock; 2 | 3 | public record PaymentTransaction( 4 | String id, 5 | String description, 6 | String recipientName, 7 | String recipientBankReference, 8 | String accountId, 9 | String paymentType, 10 | String amount, 11 | String timestamp 12 | ) {} 13 | 14 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/security/LoggedUser.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.security; 2 | 3 | public record LoggedUser(String username, String mail, String role, String displayName) { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/java/com/microsoft/openai/samples/assistant/security/LoggedUserService.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.security; 2 | 3 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 4 | import org.springframework.security.core.Authentication; 5 | import org.springframework.security.core.context.SecurityContextHolder; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Component 9 | public class LoggedUserService { 10 | 11 | public LoggedUser getLoggedUser(){ 12 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 13 | 14 | //this is always true in the PoC code 15 | if(authentication == null) { 16 | return getDefaultUser(); 17 | } 18 | //this code is never executed in the PoC. It's a hook for future improvements requiring integration with authentication providers. 19 | if (!(authentication instanceof AnonymousAuthenticationToken)) { 20 | String currentUserName = authentication.getName(); 21 | 22 | Object details = authentication.getDetails(); 23 | //object should be cast to specific type based on the authentication provider 24 | return new LoggedUser(currentUserName, "changeme@contoso.com", "changeme", "changeme"); 25 | } 26 | return getDefaultUser(); 27 | } 28 | 29 | private LoggedUser getDefaultUser() { 30 | return new LoggedUser("bob.user@contoso.com", "bob.user@contoso.com", "generic", "Bob The User"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #Used to enable mocked class to take precedence over real class in unit tests 2 | spring.main.lazy-initialization=true 3 | 4 | openai.service=${AZURE_OPENAI_SERVICE} 5 | openai.chatgpt.deployment=${AZURE_OPENAI_CHATGPT_DEPLOYMENT:gpt-4o} 6 | openai.tracing.enabled=${AZURE_OPENAI_TRACING_ENABLED:false} 7 | 8 | documentintelligence.service=${AZURE_DOCUMENT_INTELLIGENCE_SERVICE:example} 9 | 10 | 11 | storage-account.service=${AZURE_STORAGE_ACCOUNT} 12 | blob.container.name=${AZURE_STORAGE_CONTAINER:content} 13 | 14 | logging.level.com.microsoft.openai.samples.rag.ask.approaches.semantickernel=DEBUG 15 | logging.level.com.microsoft.semantickernel.samples.openapi.OpenAPIHttpRequestPlugin=DEBUG 16 | 17 | server.error.include-message=always 18 | 19 | # Support for User Assigned Managed identity 20 | azure.identity.client-id=${AZURE_CLIENT_ID:system-managed-identity} 21 | 22 | # MCP endpoints 23 | transactions.api.url=${TRANSACTIONS_API_SERVER_URL}/sse 24 | accounts.api.url=${ACCOUNTS_API_SERVER_URL}/sse 25 | payments.api.url=${PAYMENTS_API_SERVER_URL}/sse -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/main/resources/payments.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | info: 3 | title: Payment API 4 | version: 1.0.0 5 | paths: 6 | /payments: 7 | post: 8 | operationId: submitPayment 9 | summary: Submit a payment request 10 | description: Submit a payment request 11 | requestBody: 12 | required: true 13 | description: Payment to submit 14 | content: 15 | application/json: 16 | schema: 17 | $ref: '#/components/schemas/Payment' 18 | responses: 19 | '200': 20 | description: Payment request submitted successfully 21 | '400': 22 | description: Invalid request body 23 | '500': 24 | description: Internal server error 25 | components: 26 | schemas: 27 | Payment: 28 | type: object 29 | properties: 30 | description: 31 | type: string 32 | description: Description of the payment 33 | recipientName: 34 | type: string 35 | description: Name of the recipient 36 | recipientBankCode: 37 | type: string 38 | description: Bank code of the recipient 39 | accountId: 40 | type: string 41 | description: ID of the account 42 | paymentMethodId: 43 | type: string 44 | description: ID of the payment method 45 | paymentType: 46 | type: string 47 | description: 'The type of payment: creditcard, banktransfer, directdebit, visa, mastercard, paypal, etc.' 48 | amount: 49 | type: string 50 | description: Amount of the payment 51 | timestamp: 52 | type: string 53 | description: Timestamp of the payment 54 | requestBodies: 55 | Payment: 56 | content: 57 | application/json: 58 | schema: 59 | $ref: '#/components/schemas/Payment' 60 | description: Payment object to submit -------------------------------------------------------------------------------- /app/copilot/copilot-backend/src/test/java/com/microsoft/openai/samples/assistant/AccountAgentIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant; 2 | 3 | public class AccountAgentIntegrationTest { 4 | 5 | public static void main(String[] args) { 6 | 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /app/copilot/copilot-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.microsoft.openai.samples.assistant 8 | copilot-parent 9 | 1.0.0-SNAPSHOT 10 | 11 | 12 | copilot-common 13 | 14 | 15 | 16 | com.azure 17 | azure-ai-documentintelligence 18 | 19 | 20 | 21 | 22 | org.json 23 | json 24 | 20240303 25 | 26 | 27 | com.azure 28 | azure-storage-blob 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/copilot/copilot-common/src/main/java/com/microsoft/openai/samples/assistant/proxy/BlobStorageProxy.java: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | package com.microsoft.openai.samples.assistant.proxy; 3 | 4 | import com.azure.core.credential.TokenCredential; 5 | import com.azure.storage.blob.BlobClient; 6 | import com.azure.storage.blob.BlobContainerClient; 7 | import com.azure.storage.blob.BlobContainerClientBuilder; 8 | 9 | 10 | import java.io.ByteArrayInputStream; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | 14 | /** 15 | * This class is a proxy to the Blob storage API. It is responsible for: - calling the API - 16 | * handling errors and retry strategy - add monitoring points - add circuit breaker with exponential 17 | * backoff 18 | */ 19 | 20 | public class BlobStorageProxy { 21 | 22 | private final BlobContainerClient client; 23 | 24 | public BlobStorageProxy( 25 | String storageAccountServiceName, 26 | String containerName, 27 | TokenCredential tokenCredential) { 28 | 29 | String endpoint = "https://%s.blob.core.windows.net".formatted(storageAccountServiceName); 30 | this.client = 31 | new BlobContainerClientBuilder() 32 | .endpoint(endpoint) 33 | .credential(tokenCredential) 34 | .containerName(containerName) 35 | .buildClient(); 36 | } 37 | 38 | public byte[] getFileAsBytes(String fileName) throws IOException { 39 | var blobClient = client.getBlobClient(fileName); 40 | int dataSize = (int) blobClient.getProperties().getBlobSize(); 41 | 42 | // There is no need to close ByteArrayOutputStream. 43 | // https://docs.oracle.com/javase/8/docs/api/java/io/ByteArrayOutputStream.html 44 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(dataSize); 45 | blobClient.downloadStream(outputStream); 46 | 47 | return outputStream.toByteArray(); 48 | } 49 | 50 | public void storeFile(byte[] bytes, String originalFilename) { 51 | BlobClient blobClient = client.getBlobClient(originalFilename); 52 | blobClient.upload(new ByteArrayInputStream(bytes), bytes.length, true); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.microsoft.openai.samples.assistant 6 | copilot-parent 7 | 1.0.0-SNAPSHOT 8 | ../pom.xml 9 | 10 | 11 | langchain4j-agents 12 | agents implementation based on LangChain4j 13 | 14 | 15 | 16 | 17 | com.microsoft.openai.samples.assistant 18 | copilot-common 19 | 1.0.0-SNAPSHOT 20 | 21 | 22 | dev.langchain4j 23 | langchain4j-mcp 24 | 25 | ${langchain4j.version} 26 | 27 | 28 | dev.langchain4j 29 | langchain4j-azure-open-ai 30 | ${langchain4j.version} 31 | test 32 | 33 | 34 | com.azure 35 | azure-identity 36 | 37 | test 38 | 39 | 40 | org.junit.jupiter 41 | junit-jupiter-api 42 | 5.11.3 43 | test 44 | 45 | 46 | ch.qos.logback 47 | logback-classic 48 | 1.5.8 49 | test 50 | 51 | 52 | org.assertj 53 | assertj-core 54 | 3.27.3 55 | test 56 | 57 | 58 | org.wiremock 59 | wiremock 60 | 3.12.1 61 | test 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/langchain4j/agent/Agent.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.langchain4j.agent; 2 | 3 | import dev.langchain4j.data.message.ChatMessage; 4 | 5 | import java.util.List; 6 | 7 | public interface Agent { 8 | 9 | String getName(); 10 | AgentMetadata getMetadata(); 11 | List invoke(List chatHistory) throws AgentExecutionException; 12 | } 13 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/langchain4j/agent/AgentExecutionException.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.langchain4j.agent; 2 | 3 | public class AgentExecutionException extends RuntimeException { 4 | public AgentExecutionException(String message) { 5 | super(message); 6 | } 7 | 8 | public AgentExecutionException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/langchain4j/agent/AgentMetadata.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.langchain4j.agent; 2 | 3 | import java.util.List; 4 | 5 | public record AgentMetadata(String description, List intents) { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/langchain4j/agent/mcp/MCPProtocolType.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.langchain4j.agent.mcp; 2 | 3 | public enum MCPProtocolType { 4 | SSE, 5 | STDIO 6 | } 7 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/langchain4j/agent/mcp/MCPServerMetadata.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.langchain4j.agent.mcp; 2 | 3 | public record MCPServerMetadata(String serverName, String url, MCPProtocolType protocolType) { 4 | } 5 | 6 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/openai/samples/assistant/langchain4j/agent/mcp/AccountMCPAgent.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.langchain4j.agent.mcp; 2 | 3 | import com.microsoft.langchain4j.agent.AgentMetadata; 4 | import com.microsoft.langchain4j.agent.mcp.MCPProtocolType; 5 | import com.microsoft.langchain4j.agent.mcp.MCPServerMetadata; 6 | import com.microsoft.langchain4j.agent.mcp.MCPToolAgent; 7 | import dev.langchain4j.model.chat.ChatLanguageModel; 8 | import dev.langchain4j.model.input.Prompt; 9 | import dev.langchain4j.model.input.PromptTemplate; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | public class AccountMCPAgent extends MCPToolAgent { 15 | 16 | private final Prompt agentPrompt; 17 | 18 | private static final String ACCOUNT_AGENT_SYSTEM_MESSAGE = """ 19 | you are a personal financial advisor who help the user to retrieve information about their bank accounts. 20 | Use html list or table to display the account information. 21 | Always use the below logged user details to retrieve account info: 22 | '{{loggedUserName}}' 23 | """; 24 | 25 | public AccountMCPAgent(ChatLanguageModel chatModel, String loggedUserName, String accountMCPServerUrl) { 26 | super(chatModel, List.of(new MCPServerMetadata("account", accountMCPServerUrl, MCPProtocolType.SSE))); 27 | 28 | if (loggedUserName == null || loggedUserName.isEmpty()) { 29 | throw new IllegalArgumentException("loggedUserName cannot be null or empty"); 30 | } 31 | 32 | PromptTemplate promptTemplate = PromptTemplate.from(ACCOUNT_AGENT_SYSTEM_MESSAGE); 33 | this.agentPrompt = promptTemplate.apply(Map.of("loggedUserName", loggedUserName)); 34 | } 35 | 36 | @Override 37 | public String getName() { 38 | return "AccountAgent"; 39 | } 40 | 41 | @Override 42 | public AgentMetadata getMetadata() { 43 | return new AgentMetadata( 44 | "Personal financial advisor for retrieving bank account information.", 45 | List.of("RetrieveAccountInfo", "DisplayAccountDetails") 46 | ); 47 | } 48 | 49 | @Override 50 | protected String getSystemMessage() { 51 | return agentPrompt.text(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/openai/samples/assistant/langchain4j/agent/mcp/TransactionHistoryMCPAgent.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.langchain4j.agent.mcp; 2 | 3 | import com.microsoft.langchain4j.agent.AgentMetadata; 4 | import com.microsoft.langchain4j.agent.mcp.MCPProtocolType; 5 | import com.microsoft.langchain4j.agent.mcp.MCPServerMetadata; 6 | import com.microsoft.langchain4j.agent.mcp.MCPToolAgent; 7 | import dev.langchain4j.model.chat.ChatLanguageModel; 8 | import dev.langchain4j.model.input.Prompt; 9 | import dev.langchain4j.model.input.PromptTemplate; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | public class TransactionHistoryMCPAgent extends MCPToolAgent { 15 | 16 | private final Prompt agentPrompt; 17 | 18 | private static final String TRANSACTION_HISTORY_AGENT_SYSTEM_MESSAGE = """ 19 | you are a personal financial advisor who help the user with their recurrent bill payments. To search about the payments history you need to know the payee name and the account id. 20 | If the user doesn't provide the payee name, search the last 10 transactions order by date. 21 | If the user want to search last transactions for a specific payee, ask to provide the payee name. 22 | Use html list or table to display the transaction information. 23 | Always use the below logged user details to retrieve account info: 24 | '{{loggedUserName}}' 25 | Current timestamp: 26 | '{{currentDateTime}}' 27 | """; 28 | 29 | public TransactionHistoryMCPAgent(ChatLanguageModel chatModel, String loggedUserName, String transactionMCPServerUrl, String accountMCPServerUrl) { 30 | super(chatModel, List.of(new MCPServerMetadata("transaction-history", transactionMCPServerUrl, MCPProtocolType.SSE), 31 | new MCPServerMetadata("account", accountMCPServerUrl, MCPProtocolType.SSE))); 32 | 33 | if (loggedUserName == null || loggedUserName.isEmpty()) { 34 | throw new IllegalArgumentException("loggedUserName cannot be null or empty"); 35 | } 36 | 37 | PromptTemplate promptTemplate = PromptTemplate.from(TRANSACTION_HISTORY_AGENT_SYSTEM_MESSAGE); 38 | var datetimeIso8601 = java.time.ZonedDateTime.now(java.time.ZoneId.of("UTC")).toInstant().toString(); 39 | 40 | this.agentPrompt = promptTemplate.apply(Map.of( 41 | "loggedUserName", loggedUserName, 42 | "currentDateTime", datetimeIso8601 43 | )); 44 | } 45 | 46 | @Override 47 | public String getName() { 48 | return "TransactionHistoryAgent"; 49 | } 50 | 51 | @Override 52 | public AgentMetadata getMetadata() { 53 | return new AgentMetadata( 54 | "Personal financial advisor for retrieving transaction history information.", 55 | List.of("RetrieveTransactionHistory", "DisplayTransactionDetails") 56 | ); 57 | } 58 | 59 | @Override 60 | protected String getSystemMessage() { 61 | return agentPrompt.text(); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/main/java/com/microsoft/openai/samples/assistant/langchain4j/tools/InvoiceScanTool.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.openai.samples.assistant.langchain4j.tools; 2 | 3 | 4 | import com.microsoft.openai.samples.assistant.invoice.DocumentIntelligenceInvoiceScanHelper; 5 | import dev.langchain4j.agent.tool.P; 6 | import dev.langchain4j.agent.tool.Tool; 7 | import dev.langchain4j.agent.tool.ToolExecutionRequest; 8 | import dev.langchain4j.service.tool.ToolExecutor; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | 16 | public class InvoiceScanTool { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(InvoiceScanTool.class); 19 | private final DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper; 20 | public InvoiceScanTool(DocumentIntelligenceInvoiceScanHelper documentIntelligenceInvoiceScanHelper) { 21 | this.documentIntelligenceInvoiceScanHelper = documentIntelligenceInvoiceScanHelper; 22 | } 23 | @Tool( "Extract the invoice or bill data scanning a photo or image") 24 | public String scanInvoice( 25 | @P("the path to the file containing the image or photo") String filePath) { 26 | 27 | Map scanData = null; 28 | 29 | try{ 30 | scanData = documentIntelligenceInvoiceScanHelper.scan(filePath); 31 | } catch (Exception e) { 32 | LOGGER.warn("Error extracting data from invoice {}:", filePath,e); 33 | scanData = new HashMap<>(); 34 | } 35 | 36 | LOGGER.info("scanInvoice tool: Data extracted {}:{}", filePath,scanData); 37 | return scanData.toString(); 38 | 39 | } 40 | 41 | 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/test/java/dev/langchain4j/openapi/mcp/AccountMCPAgentIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package dev.langchain4j.openapi.mcp; 2 | 3 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.AccountMCPAgent; 4 | import dev.langchain4j.data.message.ChatMessage; 5 | import dev.langchain4j.data.message.UserMessage; 6 | import dev.langchain4j.model.azure.AzureOpenAiChatModel; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class AccountMCPAgentIntegrationTest { 11 | 12 | public static void main(String[] args) throws Exception { 13 | 14 | //Azure Open AI Chat Model 15 | var azureOpenAiChatModel = AzureOpenAiChatModel.builder() 16 | .apiKey(System.getenv("AZURE_OPENAI_KEY")) 17 | .endpoint(System.getenv("AZURE_OPENAI_ENDPOINT")) 18 | .deploymentName(System.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")) 19 | .temperature(0.3) 20 | .logRequestsAndResponses(true) 21 | .build(); 22 | 23 | var accountAgent = new AccountMCPAgent(azureOpenAiChatModel,"bob.user@contoso.com","http://localhost:8070/sse"); 24 | 25 | var chatHistory = new ArrayList(); 26 | chatHistory.add(UserMessage.from("How much money do I have in my account?")); 27 | 28 | accountAgent.invoke(chatHistory); 29 | System.out.println(chatHistory.get(chatHistory.size()-1)); 30 | 31 | chatHistory.add(UserMessage.from("what about my visa")); 32 | accountAgent.invoke(chatHistory); 33 | System.out.println(chatHistory.get(chatHistory.size()-1)); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/test/java/dev/langchain4j/openapi/mcp/TransactionHistoryMCPAgentIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package dev.langchain4j.openapi.mcp; 2 | 3 | import com.microsoft.openai.samples.assistant.langchain4j.agent.mcp.TransactionHistoryMCPAgent; 4 | import dev.langchain4j.data.message.ChatMessage; 5 | import dev.langchain4j.data.message.UserMessage; 6 | import dev.langchain4j.model.azure.AzureOpenAiChatModel; 7 | 8 | import java.util.ArrayList; 9 | 10 | public class TransactionHistoryMCPAgentIntegrationTest { 11 | 12 | public static void main(String[] args) throws Exception { 13 | 14 | //Azure Open AI Chat Model 15 | var azureOpenAiChatModel = AzureOpenAiChatModel.builder() 16 | .apiKey(System.getenv("AZURE_OPENAI_KEY")) 17 | .endpoint(System.getenv("AZURE_OPENAI_ENDPOINT")) 18 | .deploymentName(System.getenv("AZURE_OPENAI_DEPLOYMENT_NAME")) 19 | .temperature(0.3) 20 | .logRequestsAndResponses(true) 21 | .build(); 22 | 23 | var transactionHistoryAgent = new TransactionHistoryMCPAgent(azureOpenAiChatModel, 24 | "bob.user@contoso.com", 25 | "http://localhost:8090/sse", 26 | "http://localhost:8070/sse"); 27 | 28 | var chatHistory = new ArrayList(); 29 | 30 | 31 | chatHistory.add(UserMessage.from("When was last time I've paid contoso?")); 32 | transactionHistoryAgent.invoke(chatHistory); 33 | System.out.println(chatHistory.get(chatHistory.size()-1)); 34 | 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/copilot/langchain4j-agents/src/test/resources/payments.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.3 2 | info: 3 | title: Payment API 4 | version: 1.0.0 5 | paths: 6 | /payments: 7 | post: 8 | operationId: submitPayment 9 | summary: Submit a payment request 10 | description: Submit a payment request 11 | requestBody: 12 | required: true 13 | description: Payment to submit 14 | content: 15 | application/json: 16 | schema: 17 | $ref: '#/components/schemas/Payment' 18 | responses: 19 | '200': 20 | description: Payment request submitted successfully 21 | '400': 22 | description: Invalid request body 23 | '500': 24 | description: Internal server error 25 | components: 26 | schemas: 27 | Payment: 28 | type: object 29 | properties: 30 | description: 31 | type: string 32 | description: Description of the payment 33 | recipientName: 34 | type: string 35 | description: Name of the recipient 36 | recipientBankCode: 37 | type: string 38 | description: Bank code of the recipient 39 | accountId: 40 | type: string 41 | description: ID of the account 42 | paymentMethodId: 43 | type: string 44 | description: ID of the payment method 45 | paymentType: 46 | type: string 47 | description: 'The type of payment: creditcard, banktransfer, directdebit, visa, mastercard, paypal, etc.' 48 | amount: 49 | type: string 50 | description: Amount of the payment 51 | timestamp: 52 | type: string 53 | description: Timestamp of the payment 54 | requestBodies: 55 | Payment: 56 | content: 57 | application/json: 58 | schema: 59 | $ref: '#/components/schemas/Payment' 60 | description: Payment object to submit -------------------------------------------------------------------------------- /app/copilot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.microsoft.openai.samples.assistant 8 | copilot-parent 9 | 1.0.0-SNAPSHOT 10 | pom 11 | 12 | 13 | 17 14 | 17 15 | UTF-8 16 | 1.0.0-beta2 17 | 1.2.33 18 | 19 | 20 | 21 | 22 | 23 | com.azure 24 | azure-sdk-bom 25 | ${azure.sdk.version} 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-compiler-plugin 37 | 38 | ${maven.compiler.source} 39 | ${maven.compiler.target} 40 | 41 | 42 | 43 | 44 | 45 | 46 | copilot-backend 47 | langchain4j-agents 48 | copilot-common 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | manifests 2 | node_modules -------------------------------------------------------------------------------- /app/frontend/.env.dev: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=http://localhost:8081/api 2 | -------------------------------------------------------------------------------- /app/frontend/.env.local: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=http://localhost:8081/api 2 | -------------------------------------------------------------------------------- /app/frontend/.env.production: -------------------------------------------------------------------------------- 1 | VITE_BACKEND_URI=/api 2 | 3 | -------------------------------------------------------------------------------- /app/frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /app/frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore JSON 2 | **/*.json 3 | -------------------------------------------------------------------------------- /app/frontend/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "printWidth": 160, 4 | "arrowParens": "avoid", 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /app/frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine AS build 2 | 3 | # make the 'app' folder the current working directory 4 | WORKDIR /app 5 | 6 | COPY . . 7 | 8 | # install project dependencies 9 | RUN npm install 10 | RUN npm run build 11 | 12 | FROM nginx:alpine 13 | 14 | WORKDIR /usr/share/nginx/html 15 | COPY --from=build /app/build . 16 | COPY --from=build /app/nginx/nginx.conf.template /etc/nginx/conf.d 17 | 18 | EXPOSE 80 19 | 20 | CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/conf.d/nginx.conf.template > /etc/nginx/conf.d/default.conf && nginx -g \"daemon off;\""] 21 | -------------------------------------------------------------------------------- /app/frontend/Dockerfile-aks: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine AS build 2 | 3 | # make the 'app' folder the current working directory 4 | WORKDIR /app 5 | 6 | COPY . . 7 | 8 | 9 | # install project dependencies 10 | RUN npm install 11 | RUN npm run build 12 | 13 | FROM nginx:alpine 14 | 15 | WORKDIR /usr/share/nginx/html 16 | COPY --from=build /app/build . 17 | 18 | EXPOSE 80 19 | 20 | CMD ["/bin/sh", "-c", "nginx -g \"daemon off;\""] -------------------------------------------------------------------------------- /app/frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | GPT + Enterprise data | Java Sample 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/frontend/manifests/frontend-deployment.tmpl.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: frontend-deployment 5 | namespace: azure-open-ai 6 | labels: 7 | app: frontend 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: frontend 13 | template: 14 | metadata: 15 | labels: 16 | app: frontend 17 | spec: 18 | containers: 19 | - name: frontend 20 | image: {{.Env.SERVICE_FRONTEND_IMAGE_NAME}} 21 | imagePullPolicy: IfNotPresent 22 | ports: 23 | - containerPort: 80 24 | envFrom: 25 | - configMapRef: 26 | name: azd-env-configmap 27 | -------------------------------------------------------------------------------- /app/frontend/manifests/frontend-service.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: frontend-service 5 | namespace: azure-open-ai 6 | spec: 7 | type: ClusterIP 8 | ports: 9 | - protocol: TCP 10 | port: 80 11 | targetPort: 80 12 | selector: 13 | app: frontend 14 | -------------------------------------------------------------------------------- /app/frontend/nginx/nginx.conf.template: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | location / { 4 | root /usr/share/nginx/html; 5 | index index.html index.htm; 6 | } 7 | 8 | location /api { 9 | proxy_ssl_server_name on; 10 | proxy_http_version 1.1; 11 | proxy_pass $REACT_APP_API_BASE_URL; 12 | } 13 | } -------------------------------------------------------------------------------- /app/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "1.0.0-alpha", 5 | "type": "module", 6 | "engines": { 7 | "node": ">=14.0.0" 8 | }, 9 | "scripts": { 10 | "dev": "vite --port=8081", 11 | "build": "tsc && vite build", 12 | "preview": "vite preview" 13 | }, 14 | "dependencies": { 15 | "@azure/msal-browser": "^3.1.0", 16 | "@azure/msal-react": "^2.0.4", 17 | "@fluentui/react": "^8.112.5", 18 | "@fluentui/react-components": "^9.37.3", 19 | "@fluentui/react-icons": "^2.0.221", 20 | "@react-spring/web": "^9.7.3", 21 | "dompurify": "^3.2.4", 22 | "frontend": "file:", 23 | "ndjson-readablestream": "^1.0.7", 24 | "react": "^18.2.0", 25 | "react-dom": "^18.2.0", 26 | "react-router-dom": "^6.18.0", 27 | "scheduler": "^0.20.2" 28 | }, 29 | "devDependencies": { 30 | "@types/dompurify": "^3.0.3", 31 | "@types/react": "^18.2.34", 32 | "@types/react-dom": "^18.2.14", 33 | "@vitejs/plugin-react": "^4.3.4", 34 | "prettier": "^3.0.3", 35 | "typescript": "^5.2.2", 36 | "vite": "^6.3.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/agent-openai-java-banking-assistant/0a7fee1d6958674e1103b5d1ff729e8b716e4321/app/frontend/public/favicon.ico -------------------------------------------------------------------------------- /app/frontend/src/api/api.ts: -------------------------------------------------------------------------------- 1 | import { ChatAppResponse, ChatAppResponseOrError, ChatAppRequest } from "./models"; 2 | import { useLogin } from "../authConfig"; 3 | 4 | const BACKEND_URI = import.meta.env.VITE_BACKEND_URI ? import.meta.env.VITE_BACKEND_URI : ""; 5 | 6 | function getHeaders(idToken: string | undefined, stream:boolean): Record { 7 | var headers: Record = { 8 | "Content-Type": "application/json" 9 | }; 10 | // If using login, add the id token of the logged in account as the authorization 11 | if (useLogin) { 12 | if (idToken) { 13 | headers["Authorization"] = `Bearer ${idToken}` 14 | } 15 | } 16 | 17 | if (stream) { 18 | headers["Accept"] = "application/x-ndjson"; 19 | } else { 20 | headers["Accept"] = "application/json"; 21 | } 22 | 23 | return headers; 24 | } 25 | 26 | export async function askApi(request: ChatAppRequest, idToken: string | undefined): Promise { 27 | const response = await fetch(`${BACKEND_URI}/ask`, { 28 | method: "POST", 29 | headers: getHeaders(idToken, request.stream || false), 30 | body: JSON.stringify(request) 31 | }); 32 | 33 | const parsedResponse: ChatAppResponseOrError = await response.json(); 34 | if (response.status > 299 || !response.ok) { 35 | throw Error(parsedResponse.error || "Unknown error"); 36 | } 37 | 38 | return parsedResponse as ChatAppResponse; 39 | } 40 | 41 | export async function chatApi(request: ChatAppRequest, idToken: string | undefined): Promise { 42 | return await fetch(`${BACKEND_URI}/chat`, { 43 | method: "POST", 44 | headers: getHeaders(idToken, request.stream || false), 45 | body: JSON.stringify(request) 46 | }); 47 | } 48 | 49 | export function getCitationFilePath(citation: string): string { 50 | return `${BACKEND_URI}/content/${citation}`; 51 | } 52 | 53 | export function uploadAttachment(file: File): Promise { 54 | const formData = new FormData(); 55 | formData.append("file", file); 56 | 57 | return fetch(`${BACKEND_URI}/content`, { 58 | method: "POST", 59 | body: formData 60 | }).then(response => { 61 | if (response.status > 299 || !response.ok) { 62 | throw Error("Failed to upload attachment"); 63 | } 64 | return response.text(); 65 | }); 66 | } 67 | 68 | export function getImage(name: string): string { 69 | return `${BACKEND_URI}/content/${name}`; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /app/frontend/src/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api"; 2 | export * from "./models"; 3 | -------------------------------------------------------------------------------- /app/frontend/src/api/models.ts: -------------------------------------------------------------------------------- 1 | export const enum Approaches { 2 | JAVA_OPENAI_SDK = "jos", 3 | JAVA_SEMANTIC_KERNEL = "jsk", 4 | JAVA_SEMANTIC_KERNEL_PLANNER = "jskp" 5 | } 6 | 7 | export const enum RetrievalMode { 8 | Hybrid = "hybrid", 9 | Vectors = "vectors", 10 | Text = "text" 11 | } 12 | 13 | export const enum SKMode { 14 | Chains = "chains", 15 | Planner = "planner" 16 | } 17 | 18 | export type ChatAppRequestOverrides = { 19 | retrieval_mode?: RetrievalMode; 20 | semantic_ranker?: boolean; 21 | semantic_captions?: boolean; 22 | exclude_category?: string; 23 | top?: number; 24 | temperature?: number; 25 | prompt_template?: string; 26 | prompt_template_prefix?: string; 27 | prompt_template_suffix?: string; 28 | suggest_followup_questions?: boolean; 29 | use_oid_security_filter?: boolean; 30 | use_groups_security_filter?: boolean; 31 | semantic_kernel_mode?: SKMode; 32 | }; 33 | 34 | export type ResponseMessage = { 35 | content: string; 36 | role: string; 37 | attachments?: string[]; 38 | }; 39 | 40 | export type ResponseContext = { 41 | thoughts: string | null; 42 | data_points: string[]; 43 | }; 44 | 45 | export type ResponseChoice = { 46 | index: number; 47 | message: ResponseMessage; 48 | context: ResponseContext; 49 | session_state: any; 50 | }; 51 | 52 | export type ChatAppResponseOrError = { 53 | choices?: ResponseChoice[]; 54 | error?: string; 55 | }; 56 | 57 | export type ChatAppResponse = { 58 | choices: ResponseChoice[]; 59 | }; 60 | 61 | export type ChatAppRequestContext = { 62 | overrides?: ChatAppRequestOverrides; 63 | }; 64 | 65 | export type ChatAppRequest = { 66 | messages: ResponseMessage[]; 67 | approach: Approaches; 68 | context?: ChatAppRequestContext; 69 | stream?: boolean; 70 | session_state: any; 71 | }; 72 | -------------------------------------------------------------------------------- /app/frontend/src/assets/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/frontend/src/assets/search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/frontend/src/components/AnalysisPanel/AnalysisPanel.module.css: -------------------------------------------------------------------------------- 1 | .thoughtProcess { 2 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 3 | word-wrap: break-word; 4 | padding-top: 12px; 5 | padding-bottom: 12px; 6 | } 7 | -------------------------------------------------------------------------------- /app/frontend/src/components/AnalysisPanel/AnalysisPanel.tsx: -------------------------------------------------------------------------------- 1 | import { Pivot, PivotItem } from "@fluentui/react"; 2 | import DOMPurify from "dompurify"; 3 | 4 | import styles from "./AnalysisPanel.module.css"; 5 | 6 | import { SupportingContent } from "../SupportingContent"; 7 | import { ChatAppResponse } from "../../api"; 8 | import { AnalysisPanelTabs } from "./AnalysisPanelTabs"; 9 | 10 | interface Props { 11 | className: string; 12 | activeTab: AnalysisPanelTabs; 13 | onActiveTabChanged: (tab: AnalysisPanelTabs) => void; 14 | activeCitation: string | undefined; 15 | citationHeight: string; 16 | answer: ChatAppResponse; 17 | } 18 | 19 | const pivotItemDisabledStyle = { disabled: true, style: { color: "grey" } }; 20 | 21 | export const AnalysisPanel = ({ answer, activeTab, activeCitation, citationHeight, className, onActiveTabChanged }: Props) => { 22 | const isDisabledThoughtProcessTab: boolean = !answer.choices[0].context.thoughts; 23 | const isDisabledSupportingContentTab: boolean = !answer.choices[0].context.data_points.length; 24 | const isDisabledCitationTab: boolean = !activeCitation; 25 | 26 | const sanitizedThoughts = DOMPurify.sanitize(answer.choices[0].context.thoughts!); 27 | 28 | return ( 29 | pivotItem && onActiveTabChanged(pivotItem.props.itemKey! as AnalysisPanelTabs)} 33 | > 34 | 39 |
40 |
41 | 46 | 47 | 48 | 53 |