From 83e0201ea1d7f33888b66034433ef71c94081f2b Mon Sep 17 00:00:00 2001 From: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com> Date: Fri, 11 Aug 2023 08:58:50 -0700 Subject: [PATCH 01/18] =?UTF-8?q?=F0=9F=9A=80=20Adding=20new=20app=20state?= =?UTF-8?q?=20to=20handle=20user=20info=20(#145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Motivation and Context Added new app state for setting user info, refactored app views, and added shared styles for informative views. This is a fix for a bug where the webapp would get stuck on the Loading Chats page. Something with SSO caused this. ### Description - The App component now transitions to a SettingUserInfo state after successfully discovering the backend, and then to the LoadingChats state after successfully setting the active user info. - The user info status text in the App component has been updated to display a default message while fetching user information, and an error component has been added to display an error message at view level. - A new useSharedClasses hook has been added to provide a set of shared styles for informative views. - The BackendProbe component has also been updated to use the shared informativeView class. - Added tesseract data files to gitignore ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations ~~- [ ] All unit tests pass, and I have added new tests where possible~~ - [x] I didn't break anyone :smile: --- .gitignore | 5 ++- webapp/src/App.tsx | 47 +++++++++++--------- webapp/src/components/views/BackendProbe.tsx | 8 ++-- webapp/src/components/views/Error.tsx | 20 +++++++++ webapp/src/components/views/Loading.tsx | 8 ++-- webapp/src/components/views/index.ts | 6 +++ webapp/src/styles.tsx | 11 +++++ 7 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 webapp/src/components/views/Error.tsx create mode 100644 webapp/src/components/views/index.ts diff --git a/.gitignore b/.gitignore index f09d4d638..719f5ba7d 100644 --- a/.gitignore +++ b/.gitignore @@ -483,4 +483,7 @@ webapp/node_modules/ webapp/public/.well-known* # Auto-generated solution file from Visual Studio -webapi/CopilotChatWebApi.sln \ No newline at end of file +webapi/CopilotChatWebApi.sln + +# Tesseract OCR language data files +*.traineddata \ No newline at end of file diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 6fc5f0f5b..c89bffefe 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -7,16 +7,12 @@ import * as React from 'react'; import { FC, useEffect } from 'react'; import { UserSettingsMenu } from './components/header/UserSettingsMenu'; import { PluginGallery } from './components/open-api-plugins/PluginGallery'; -import BackendProbe from './components/views/BackendProbe'; -import { ChatView } from './components/views/ChatView'; -import Loading from './components/views/Loading'; -import { Login } from './components/views/Login'; +import { BackendProbe, ChatView, Error, Loading, Login } from './components/views'; import { useChat } from './libs/hooks'; -import { AlertType } from './libs/models/AlertType'; import { useAppDispatch, useAppSelector } from './redux/app/hooks'; import { RootState } from './redux/app/store'; import { FeatureKeys } from './redux/features/app/AppState'; -import { addAlert, setActiveUserInfo, setServiceOptions } from './redux/features/app/appSlice'; +import { setActiveUserInfo, setServiceOptions } from './redux/features/app/appSlice'; import { semanticKernelDarkTheme, semanticKernelLightTheme } from './styles'; export const useClasses = makeStyles({ @@ -51,6 +47,8 @@ export const useClasses = makeStyles({ enum AppState { ProbeForBackend, + SettingUserInfo, + ErrorLoadingUserInfo, LoadingChats, Chat, SigningOut, @@ -70,21 +68,24 @@ const App: FC = () => { useEffect(() => { if (isAuthenticated) { - let isActiveUserInfoSet = activeUserInfo !== undefined; - if (!isActiveUserInfoSet) { - const account = instance.getActiveAccount(); - if (!account) { - dispatch(addAlert({ type: AlertType.Error, message: 'Unable to get active logged in account.' })); + if (appState === AppState.SettingUserInfo) { + if (activeUserInfo === undefined) { + const account = instance.getActiveAccount(); + if (!account) { + setAppState(AppState.ErrorLoadingUserInfo); + } else { + dispatch( + setActiveUserInfo({ + id: account.homeAccountId, + email: account.username, // username in an AccountInfo object is the email address + username: account.name ?? account.username, + }), + ); + setAppState(AppState.LoadingChats); + } } else { - dispatch( - setActiveUserInfo({ - id: account.homeAccountId, - email: account.username, // username in an AccountInfo object is the email address - username: account.name ?? account.username, - }), - ); + setAppState(AppState.LoadingChats); } - isActiveUserInfoSet = true; } if (appState === AppState.LoadingChats) { @@ -143,10 +144,16 @@ const App: FC = () => { { - setAppState(AppState.LoadingChats); + setAppState(AppState.SettingUserInfo); }} /> )} + {appState === AppState.SettingUserInfo && ( + + )} + {appState === AppState.ErrorLoadingUserInfo && ( + + )} {appState === AppState.LoadingChats && } {appState === AppState.Chat && } diff --git a/webapp/src/components/views/BackendProbe.tsx b/webapp/src/components/views/BackendProbe.tsx index 266963b86..f160ed859 100644 --- a/webapp/src/components/views/BackendProbe.tsx +++ b/webapp/src/components/views/BackendProbe.tsx @@ -2,13 +2,15 @@ import { Body1, Spinner, Title3 } from '@fluentui/react-components'; import { FC, useEffect } from 'react'; +import { useSharedClasses } from '../../styles'; interface IData { uri: string; onBackendFound: () => void; } -const BackendProbe: FC = ({ uri, onBackendFound }) => { +export const BackendProbe: FC = ({ uri, onBackendFound }) => { + const classes = useSharedClasses(); useEffect(() => { const timer = setInterval(() => { const requestUrl = new URL('healthz', uri); @@ -31,7 +33,7 @@ const BackendProbe: FC = ({ uri, onBackendFound }) => { }); return ( -
+
Looking for your backend @@ -45,5 +47,3 @@ const BackendProbe: FC = ({ uri, onBackendFound }) => {
); }; - -export default BackendProbe; diff --git a/webapp/src/components/views/Error.tsx b/webapp/src/components/views/Error.tsx new file mode 100644 index 000000000..13c53c629 --- /dev/null +++ b/webapp/src/components/views/Error.tsx @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All rights reserved. + +import { Subtitle2 } from '@fluentui/react-components'; +import { ErrorCircleRegular } from '@fluentui/react-icons'; +import { FC } from 'react'; +import { useSharedClasses } from '../../styles'; + +interface IErrorProps { + text: string; +} + +export const Error: FC = ({ text }) => { + const classes = useSharedClasses(); + return ( +
+ + {text} +
+ ); +}; diff --git a/webapp/src/components/views/Loading.tsx b/webapp/src/components/views/Loading.tsx index de36a3057..3a9640206 100644 --- a/webapp/src/components/views/Loading.tsx +++ b/webapp/src/components/views/Loading.tsx @@ -2,17 +2,17 @@ import { Spinner } from '@fluentui/react-components'; import { FC } from 'react'; +import { useSharedClasses } from '../../styles'; interface ILoadingProps { text: string; } -const Loading: FC = ({ text }) => { +export const Loading: FC = ({ text }) => { + const classes = useSharedClasses(); return ( -
+
); }; - -export default Loading; diff --git a/webapp/src/components/views/index.ts b/webapp/src/components/views/index.ts new file mode 100644 index 000000000..5fcc763a8 --- /dev/null +++ b/webapp/src/components/views/index.ts @@ -0,0 +1,6 @@ +export * from './BackendProbe'; +export * from './ChatView'; +export * from './Error'; +export * from './Loading'; +export * from './Login'; +export * from './MissingEnvVariablesError'; diff --git a/webapp/src/styles.tsx b/webapp/src/styles.tsx index 54e964334..e6374aad0 100644 --- a/webapp/src/styles.tsx +++ b/webapp/src/styles.tsx @@ -74,6 +74,17 @@ export const SharedStyles: Record = { }, }; +export const useSharedClasses = makeStyles({ + informativeView: { + display: 'flex', + flexDirection: 'column', + ...shorthands.padding('80px'), + alignItems: 'center', + ...shorthands.gap(tokens.spacingVerticalXL), + marginTop: tokens.spacingVerticalXXXL, + }, +}); + export const useDialogClasses = makeStyles({ root: { height: '515px', From 4c48766b4e39d7cb3dbd942bab962c3c33ac86ae Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Fri, 11 Aug 2023 14:44:10 -0700 Subject: [PATCH 02/18] Updating template hash. (#162) Updating template hash to match bicep file. - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone :smile: Co-authored-by: Ben Thomas --- scripts/deploy/main.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/deploy/main.json b/scripts/deploy/main.json index 8687527fd..3e27026dd 100644 --- a/scripts/deploy/main.json +++ b/scripts/deploy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.19.5.34762", - "templateHash": "12182074692341112389" + "version": "0.20.4.51522", + "templateHash": "15530074115758293206" } }, "parameters": { From e501d7f622f5b7ae9278d7ca4f71049ccf1f800e Mon Sep 17 00:00:00 2001 From: Mollie Munoz Date: Fri, 11 Aug 2023 17:50:58 -0700 Subject: [PATCH 03/18] Update Readme with note on execution policy. (#161) ### Motivation and Context A user has been unable to run the primary Readme ps scripts (e.g., scripts\Install.ps1) due to the error: "File cannot be loaded. The file is not digitally signed. You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies at https:/go.microsoft.com/fwlink/?LinkID=135170." ### Description Adds note directing user to official documentation pages on changing execution policy or unblocking the script. ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone :smile: --------- Co-authored-by: Mollie Munoz --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5bff2ea9e..f07314291 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,14 @@ You will need the following items to run the sample: 1. Open PowerShell as an administrator. 2. Setup your environment. - ```powershell - cd \scripts\ - .\Install.ps1 - ``` - - > NOTE: This script will install `Chocolatey`, `dotnet-7.0-sdk`, `nodejs`, and `yarn`. + ```powershell + cd \scripts\ + .\Install.ps1 + ``` + + > NOTE: This script will install `Chocolatey`, `dotnet-7.0-sdk`, `nodejs`, and `yarn`. + + > NOTE: If you receive an error that the script is not digitally signed or cannot execute on the system, you may need to [change the execution policy](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3#change-the-execution-policy) (see list of [policies](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3#powershell-execution-policies) and [scopes](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.3#execution-policy-scope)) or [unblock the script](https://learn.microsoft.com/powershell/module/microsoft.powershell.security/get-executionpolicy?view=powershell-7.3#example-4-unblock-a-script-to-run-it-without-changing-the-execution-policy). 3. Configure Chat Copilot. From f921dbc5117c81e4af3a1fa26d1810cb59f0eaf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:29:15 -0700 Subject: [PATCH 04/18] Bump eslint from 8.46.0 to 8.47.0 in /webapp (#167) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [eslint](https://github.com/eslint/eslint) from 8.46.0 to 8.47.0.
Release notes

Sourced from eslint's releases.

v8.47.0

Features

  • 53d7508 feat: update regex for methods with thisArg (#17439) (Francesco Trotta)

Bug Fixes

  • 631648e fix: do not report on shadowed constructors in no-new-wrappers (#17447) (Francesco Trotta)

Documentation

  • a766a48 docs: document lack of config file names (#17442) (James)
  • a1635d6 docs: Update README (GitHub Actions Bot)
  • 47a0859 docs: update require-unicode-regexp.md as following up #17402 (#17441) (SUZUKI Sosuke)
  • fcdc85d docs: Update README (GitHub Actions Bot)
  • 2a92b6c docs: update with "Specifying Parser Options" (#17435) (Cheol-Won)
  • d743ed3 docs: add metadata for parser/processor (#17438) (Huáng Jùnliàng)
  • 224376c docs: Update README (GitHub Actions Bot)
  • a41a8e4 docs: update script names in README (#17432) (Nitin Kumar)

Chores

  • bf69aa6 chore: Update dependencies (#17456) (Nicholas C. Zakas)
  • 0e45760 chore: package.json update for @​eslint/js release (ESLint Jenkins)
  • 757bfe1 chore: Remove add-to-triage (#17450) (Nicholas C. Zakas)
  • b066640 chore: standardize npm script names (#17431) (Nitin Kumar)
  • 6b2410f chore: Update add-to-triage.yml (#17444) (Nicholas C. Zakas)
Changelog

Sourced from eslint's changelog.

v8.47.0 - August 11, 2023

  • bf69aa6 chore: Update dependencies (#17456) (Nicholas C. Zakas)
  • 0e45760 chore: package.json update for @​eslint/js release (ESLint Jenkins)
  • 631648e fix: do not report on shadowed constructors in no-new-wrappers (#17447) (Francesco Trotta)
  • 757bfe1 chore: Remove add-to-triage (#17450) (Nicholas C. Zakas)
  • b066640 chore: standardize npm script names (#17431) (Nitin Kumar)
  • a766a48 docs: document lack of config file names (#17442) (James)
  • a1635d6 docs: Update README (GitHub Actions Bot)
  • 6b2410f chore: Update add-to-triage.yml (#17444) (Nicholas C. Zakas)
  • 47a0859 docs: update require-unicode-regexp.md as following up #17402 (#17441) (SUZUKI Sosuke)
  • 53d7508 feat: update regex for methods with thisArg (#17439) (Francesco Trotta)
  • fcdc85d docs: Update README (GitHub Actions Bot)
  • 2a92b6c docs: update with "Specifying Parser Options" (#17435) (Cheol-Won)
  • d743ed3 docs: add metadata for parser/processor (#17438) (Huáng Jùnliàng)
  • 224376c docs: Update README (GitHub Actions Bot)
  • a41a8e4 docs: update script names in README (#17432) (Nitin Kumar)
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eslint&package-manager=npm_and_yarn&previous-version=8.46.0&new-version=8.47.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapp/package.json | 2 +- webapp/yarn.lock | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 221994b98..08014f59b 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -37,7 +37,7 @@ "@types/react-dom": "^18.0.11", "@typescript-eslint/eslint-plugin": "^6.2.1", "@typescript-eslint/parser": "^6.2.1", - "eslint": "^8.46.0", + "eslint": "^8.47.0", "prettier": "^3.0.1", "react-scripts": "^5.0.1", "serve": "^14.2.0", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 8b6296e38..82f70b907 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -1311,10 +1311,10 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== -"@eslint/eslintrc@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.1.tgz#18d635e24ad35f7276e8a49d135c7d3ca6a46f93" - integrity sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA== +"@eslint/eslintrc@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" + integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1326,10 +1326,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@^8.46.0": - version "8.46.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6" - integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA== +"@eslint/js@^8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.47.0.tgz#5478fdf443ff8158f9de171c704ae45308696c7d" + integrity sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og== "@floating-ui/core@^1.3.1": version "1.3.1" @@ -5395,10 +5395,10 @@ eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f" - integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint-webpack-plugin@^3.1.1: version "3.2.0" @@ -5411,15 +5411,15 @@ eslint-webpack-plugin@^3.1.1: normalize-path "^3.0.0" schema-utils "^4.0.0" -eslint@^8.3.0, eslint@^8.46.0: - version "8.46.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.46.0.tgz#a06a0ff6974e53e643acc42d1dcf2e7f797b3552" - integrity sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg== +eslint@^8.3.0, eslint@^8.47.0: + version "8.47.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.47.0.tgz#c95f9b935463fb4fad7005e626c7621052e90806" + integrity sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.1" - "@eslint/js" "^8.46.0" + "@eslint/eslintrc" "^2.1.2" + "@eslint/js" "^8.47.0" "@humanwhocodes/config-array" "^0.11.10" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" @@ -5430,7 +5430,7 @@ eslint@^8.3.0, eslint@^8.46.0: doctrine "^3.0.0" escape-string-regexp "^4.0.0" eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.2" + eslint-visitor-keys "^3.4.3" espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" From d16d801aaf308816dfe166764586347ffa4d5100 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:29:20 -0700 Subject: [PATCH 05/18] Bump @azure/msal-browser from 2.38.0 to 2.38.1 in /webapp (#168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [@azure/msal-browser](https://github.com/AzureAD/microsoft-authentication-library-for-js) from 2.38.0 to 2.38.1.
Release notes

Sourced from @​azure/msal-browser's releases.

@​azure/msal-browser v2.38.1

2.38.1

Mon, 07 Aug 2023 21:58:26 GMT

Patches

Discussion: https://github.com/AzureAD/microsoft-authentication-library-for-js/discussions/6297

Commits
  • 2819735 Expose "CacheRecord" as part of internals API (#6291)
  • f772f1c Remove beta tags from publish commands (#6287)
  • b9fd236 Update certificate-credentials.md (#6275)
  • 2a169dc Revert allowNativeBroker default to false (#6280)
  • 8cbd07c Append v2 to endpoint when using a Microsoft authority under OIDC protocol mo...
  • 8c382b3 Hydrate cache API (#6271)
  • e698e4e Remove derisen from CODEOWNERS (#6279)
  • d8b4b70 Add storeInCache request parameter to control which tokens are persisted to t...
  • e498fa3 Expose BrowserPerformanceClient and BrowserPerformanceMeasurement artifac...
  • 396f5b2 Disable telemetry parameters in the token request when using OIDC protocol mo...
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@azure/msal-browser&package-manager=npm_and_yarn&previous-version=2.38.0&new-version=2.38.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapp/package.json | 2 +- webapp/yarn.lock | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 08014f59b..00f9028f6 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -15,7 +15,7 @@ "eject": "react-scripts eject" }, "dependencies": { - "@azure/msal-browser": "^2.32.1", + "@azure/msal-browser": "^2.38.1", "@azure/msal-react": "^1.5.1", "@fluentui/react-components": "^9.27.4", "@fluentui/react-icons": "^2.0.209", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 82f70b907..dc84db212 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -29,17 +29,17 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@azure/msal-browser@^2.32.1": - version "2.38.0" - resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.38.0.tgz#c3621dc4cc9bf8c5589ec3e4474a63d6985ebd6b" - integrity sha512-gxBh83IumHgEP9uMCm9pJLKLRwICMQTxG9TX3AytdNt3oLUI3tytm/szYD5u5zKJgSkhHvwFSM+NPnM04hYw3w== +"@azure/msal-browser@^2.38.1": + version "2.38.1" + resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-2.38.1.tgz#4bdc2c4820dedd569c2a203e0167815a541c04fa" + integrity sha512-NROo7mLpw7aWtj8tWy9ZPz3WWiudwVAOIDZ1K3PPrjDAA4kFYayWlbZiJl1T1sD5Oqwa6FOtwzFSvuUj1CWp6Q== dependencies: - "@azure/msal-common" "13.2.0" + "@azure/msal-common" "13.2.1" -"@azure/msal-common@13.2.0": - version "13.2.0" - resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.2.0.tgz#e3c6e35c0bf96ea59deaab08286a7b51b9d1ec91" - integrity sha512-rnstQ7Zgn3fSTKNQO+/YNV34/QXJs0vni7IA0/3QB1EEyrJg14xyRmTqlw9ta+pdSuT5OJwUP8kI3D/rBwUIBw== +"@azure/msal-common@13.2.1": + version "13.2.1" + resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-13.2.1.tgz#64f2c42d35df1c6ee0ea9ac03ba127482dd8692c" + integrity sha512-9CtyVdDtAOw+raemKg8gdBuE7gleObgSb7p4bzMIlUt8eM69/Gaow7uqr1gK3jLYINSrss32OZW8mBbdgVLiHg== "@azure/msal-react@^1.5.1": version "1.5.9" From ef6da3194439cacf5ff1f4e297de970a5f884ebd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:31:05 -0700 Subject: [PATCH 06/18] Bump Microsoft.Azure.Cosmos from 3.35.2 to 3.35.3 in /webapi (#173) Bumps [Microsoft.Azure.Cosmos](https://github.com/Azure/azure-cosmos-dotnet-v3) from 3.35.2 to 3.35.3.
Release notes

Sourced from Microsoft.Azure.Cosmos's releases.

3.35.3

3.35.3 - 2023-08-10

Fixed

  • 4030 Upgrade Resiliency: Fixes Race Condition by Calling Dispose Too Early

Added

  • 4019 Upgrade Resiliency: Disables Replica Validation Feature By Default in Preview (The feature was previously enabled by default in the 3.35.2-preview release)

3.35.3-preview

3.35.3-preview - 2023-08-10

Fixed

  • 4030 Upgrade Resiliency: Fixes Race Condition by Calling Dispose Too Early

Added

  • 4019 Upgrade Resiliency: Disables Replica Validation Feature By Default in Preview (The feature was previously enabled by default in the 3.35.2-preview release)
Changelog

Sourced from Microsoft.Azure.Cosmos's changelog.

3.35.3 - 2023-08-10

Fixed

  • 4030 Upgrade Resiliency: Fixes Race Condition by Calling Dispose Too Early

Added

  • 4019 Upgrade Resiliency: Disables Replica Validation Feature By Default in Preview (The feature was previously enabled by default in the 3.35.2-preview release)

3.35.2-preview - 2023-07-17

Fixed

  • 3973 Application Insights Integration: Fixes event generation for failed requests

Added

  • 3951 Upgrade Resiliency: Adds Code to Enable Replica Validation Feature By Default for Preview
Commits
  • aff544b [Hotfix] Upgrade Resiliency: Refactors Code to Disable Replica Validation Fea...
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Azure.Cosmos&package-manager=nuget&previous-version=3.35.2&new-version=3.35.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapi/CopilotChatWebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index 0ce24a154..66abd0588 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -11,7 +11,7 @@ - + From c0e111dbbc3449cc801c8f38a3a9b31f9fd50c7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:31:07 -0700 Subject: [PATCH 07/18] Bump @types/node from 20.4.5 to 20.5.0 in /webapp (#171) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.4.5 to 20.5.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@types/node&package-manager=npm_and_yarn&previous-version=20.4.5&new-version=20.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapp/package.json | 2 +- webapp/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 00f9028f6..edd61c6d1 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -32,7 +32,7 @@ "devDependencies": { "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@types/debug": "^4.1.7", - "@types/node": "^20.4.4", + "@types/node": "^20.5.0", "@types/react": "^18.2.18", "@types/react-dom": "^18.0.11", "@typescript-eslint/eslint-plugin": "^6.2.1", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index dc84db212..adeb59539 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -3033,10 +3033,10 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node@*", "@types/node@^20.4.4": - version "20.4.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.5.tgz#9dc0a5cb1ccce4f7a731660935ab70b9c00a5d69" - integrity sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg== +"@types/node@*", "@types/node@^20.5.0": + version "20.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" + integrity sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q== "@types/parse-json@^4.0.0": version "4.0.0" From 7b2a1a848e664adbb749f978a6a899264a114b56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:31:45 -0700 Subject: [PATCH 08/18] Bump Microsoft.VisualStudio.Threading.Analyzers from 17.6.40 to 17.7.30 in /webapi (#174) Bumps [Microsoft.VisualStudio.Threading.Analyzers](https://github.com/microsoft/vs-threading) from 17.6.40 to 17.7.30.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.VisualStudio.Threading.Analyzers&package-manager=nuget&previous-version=17.6.40&new-version=17.7.30)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapi/CopilotChatWebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index 66abd0588..861bc9799 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -46,7 +46,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive
- + all runtime; build; native; contentfiles; analyzers; buildtransitive From 002651a6340fa3209cb1b5caac1391cdfd928ad2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:35:41 +0000 Subject: [PATCH 09/18] Bump @typescript-eslint/parser from 6.2.1 to 6.3.0 in /webapp (#169) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.2.1 to 6.3.0.
Release notes

Sourced from @​typescript-eslint/parser's releases.

v6.3.0

6.3.0 (2023-08-07)

Bug Fixes

  • eslint-plugin: [no-extra-parens] keep parens around call expression arguments when type arguments contain parens (#7375) (38e5e4e)
  • eslint-plugin: [no-restricted-imports] allow inline type qualifiers when allowTypeImports enabled (#7379) (cc9a46d)

Features

  • eslint-plugin: [prefer-nullish-coalescing] allow ignorePrimitives option to be true (#7331) (dfcafae)

You can read about our versioning strategy and releases on our website.

Changelog

Sourced from @​typescript-eslint/parser's changelog.

6.3.0 (2023-08-07)

Note: Version bump only for package @​typescript-eslint/parser

You can read about our versioning strategy and releases on our website.

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@typescript-eslint/parser&package-manager=npm_and_yarn&previous-version=6.2.1&new-version=6.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapp/package.json | 2 +- webapp/yarn.lock | 50 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index edd61c6d1..7ce3e57e5 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -36,7 +36,7 @@ "@types/react": "^18.2.18", "@types/react-dom": "^18.0.11", "@typescript-eslint/eslint-plugin": "^6.2.1", - "@typescript-eslint/parser": "^6.2.1", + "@typescript-eslint/parser": "^6.3.0", "eslint": "^8.47.0", "prettier": "^3.0.1", "react-scripts": "^5.0.1", diff --git a/webapp/yarn.lock b/webapp/yarn.lock index adeb59539..ea040e81c 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -3229,15 +3229,15 @@ "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" -"@typescript-eslint/parser@^6.2.1": - version "6.2.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.2.1.tgz#e18a31eea1cca8841a565f1701960c8123ed07f9" - integrity sha512-Ld+uL1kYFU8e6btqBFpsHkwQ35rw30IWpdQxgOqOh4NfxSDH6uCkah1ks8R/RgQqI5hHPXMaLy9fbFseIe+dIg== +"@typescript-eslint/parser@^6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.3.0.tgz#359684c443f4f848db3c4f14674f544f169c8f46" + integrity sha512-ibP+y2Gr6p0qsUkhs7InMdXrwldjxZw66wpcQq9/PzAroM45wdwyu81T+7RibNCh8oc0AgrsyCwJByncY0Ongg== dependencies: - "@typescript-eslint/scope-manager" "6.2.1" - "@typescript-eslint/types" "6.2.1" - "@typescript-eslint/typescript-estree" "6.2.1" - "@typescript-eslint/visitor-keys" "6.2.1" + "@typescript-eslint/scope-manager" "6.3.0" + "@typescript-eslint/types" "6.3.0" + "@typescript-eslint/typescript-estree" "6.3.0" + "@typescript-eslint/visitor-keys" "6.3.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": @@ -3256,6 +3256,14 @@ "@typescript-eslint/types" "6.2.1" "@typescript-eslint/visitor-keys" "6.2.1" +"@typescript-eslint/scope-manager@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.3.0.tgz#6b74e338c4b88d5e1dfc1a28c570dd5cf8c86b09" + integrity sha512-WlNFgBEuGu74ahrXzgefiz/QlVb+qg8KDTpknKwR7hMH+lQygWyx0CQFoUmMn1zDkQjTBBIn75IxtWss77iBIQ== + dependencies: + "@typescript-eslint/types" "6.3.0" + "@typescript-eslint/visitor-keys" "6.3.0" + "@typescript-eslint/type-utils@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" @@ -3286,6 +3294,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.2.1.tgz#7fcdeceb503aab601274bf5e210207050d88c8ab" integrity sha512-528bGcoelrpw+sETlyM91k51Arl2ajbNT9L4JwoXE2dvRe1yd8Q64E4OL7vHYw31mlnVsf+BeeLyAZUEQtqahQ== +"@typescript-eslint/types@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.3.0.tgz#84517f1427923e714b8418981e493b6635ab4c9d" + integrity sha512-K6TZOvfVyc7MO9j60MkRNWyFSf86IbOatTKGrpTQnzarDZPYPVy0oe3myTMq7VjhfsUAbNUW8I5s+2lZvtx1gg== + "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -3312,6 +3325,19 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.3.0.tgz#20e1e10e2f51cdb9e19a2751215cac92c003643c" + integrity sha512-Xh4NVDaC4eYKY4O3QGPuQNp5NxBAlEvNQYOqJquR2MePNxO11E5K3t5x4M4Mx53IZvtpW+mBxIT0s274fLUocg== + dependencies: + "@typescript-eslint/types" "6.3.0" + "@typescript-eslint/visitor-keys" "6.3.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.58.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" @@ -3355,6 +3381,14 @@ "@typescript-eslint/types" "6.2.1" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@6.3.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.3.0.tgz#8d09aa3e389ae0971426124c155ac289afbe450a" + integrity sha512-kEhRRj7HnvaSjux1J9+7dBen15CdWmDnwrpyiHsFX6Qx2iW5LOBUgNefOFeh2PjWPlNwN8TOn6+4eBU3J/gupw== + dependencies: + "@typescript-eslint/types" "6.3.0" + eslint-visitor-keys "^3.4.1" + "@uifabric/set-version@^7.0.24": version "7.0.24" resolved "https://registry.yarnpkg.com/@uifabric/set-version/-/set-version-7.0.24.tgz#8c67d8f1d67c1636a170efa8b622132da2d294a9" From 134d42cb31ffab5debe152c2df090bbea90fdd46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:37:34 -0700 Subject: [PATCH 10/18] Bump microsoft-cognitiveservices-speech-sdk from 1.30.1 to 1.31.0 in /webapp (#170) Bumps [microsoft-cognitiveservices-speech-sdk](https://github.com/Microsoft/cognitive-services-speech-sdk-js) from 1.30.1 to 1.31.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=microsoft-cognitiveservices-speech-sdk&package-manager=npm_and_yarn&previous-version=1.30.1&new-version=1.31.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapp/package.json | 2 +- webapp/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index 7ce3e57e5..08c841888 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -24,7 +24,7 @@ "@playwright/test": "^1.35.1", "@reduxjs/toolkit": "^1.9.1", "debug": "^4.3.4", - "microsoft-cognitiveservices-speech-sdk": "^1.27.0", + "microsoft-cognitiveservices-speech-sdk": "^1.31.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.1.2" diff --git a/webapp/yarn.lock b/webapp/yarn.lock index ea040e81c..042cc416c 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -7590,10 +7590,10 @@ micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -microsoft-cognitiveservices-speech-sdk@^1.27.0: - version "1.30.1" - resolved "https://registry.yarnpkg.com/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.30.1.tgz#80ad5fc3a1986569881e432694099c857e5c8497" - integrity sha512-pR/abkc55hvUOG1TSmJ79Mt+A+/9R5TVeuvMaJCcvHYroIPVdG5eXqzIiZNxuy5P0x+YICYnPSOQMoHyPgtN1Q== +microsoft-cognitiveservices-speech-sdk@^1.31.0: + version "1.31.0" + resolved "https://registry.yarnpkg.com/microsoft-cognitiveservices-speech-sdk/-/microsoft-cognitiveservices-speech-sdk-1.31.0.tgz#a90d59f4205f58d072ed3d4439fa35b07d908ec0" + integrity sha512-wmNi0XoGtQwRoI2To6QSrGHVW0d8WfhJwXtE2nk48l4YkBiDqdPV2tdSXFHRrdv3uwr/+THip45H91Fllpm8qA== dependencies: agent-base "^6.0.1" bent "^7.3.12" From 30a2fda6c2711c54b1bbe554fa248fb0f5edfc93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 09:37:43 -0700 Subject: [PATCH 11/18] Bump Azure.AI.FormRecognizer from 4.0.0 to 4.1.0 in /webapi (#172) Bumps [Azure.AI.FormRecognizer](https://github.com/Azure/azure-sdk-for-net) from 4.0.0 to 4.1.0.
Release notes

Sourced from Azure.AI.FormRecognizer's releases.

Azure.AI.FormRecognizer_4.1.0

4.1.0 (2023-08-10)

Features Added

  • In struct DocumentAnalysisFeature, added properties Barcodes, KeyValuePairs, and Languages as add-on capabilities.
  • Added class DocumentContentSource as a base class to AzureBlobContentSource (renamed to BlobContentSource in this SDK version) and AzureBlobFileListSource (renamed to BlobFileListContentSource in this SDK version).
  • In DocumentModelAdministrationClient, added a new overload to BuildDocumentModel that takes a DocumentContentSource object. It can be used to build a document model from alternative content sources.
  • Added property ServiceVersion to classes AnalyzeResult, DocumentModelDetails, DocumentModelSummary, OperationDetails, and OperationSummary.

Breaking Changes

  • DocumentAnalysisClient and DocumentModelAdministrationClient now target service API version 2023-07-31 by default. Version 2023-02-28-preview is not supported anymore.
  • In struct DocumentAnalysisFeature, properties OcrFormula and OcrFont were renamed to Formulas and FontStyling, respectively.
  • Removed query fields support. The properties AnalyzeDocumentOptions.QueryFields and DocumentAnalysisFeature.QueryFieldsPremium were removed.
  • Removed image extraction support. The class DocumentImage and the property DocumentPage.Images were removed.
  • Removed annotation extraction support. The types DocumentAnnotation, DocumentAnnotationKind, and the property DocumentPage.Annotations were removed.
  • Removed struct DocumentPageKind and property DocumentPage.Kind.
  • Removed property DocumentKeyValuePair.CommonName.
  • In DocumentBarcodeKind, renamed members QRCode, PDF417, EAN8, EAN13, ITF, and MicroQRCode to QrCode, Pdf417, Ean8, Ean13, Itf, and MicroQrCode, respectively.
  • Renamed class AzureBlobContentSource to BlobContentSource.
  • Renamed class AzureBlobFileListSource to BlobFileListContentSource.
  • In class ClassifierDocumentTypeDetails, properties AzureBlobFileListSource and AzureBlobSource have been replaced by a single polymorphic property TrainingDataSource.
  • In class ClassifierDocumentTypeDetails, all constructors have been replaced by a single constructor that takes a polymorphic parameter trainingDataSource.
  • In class ResourceDetails, renamed property CustomNeuralDocumentModelBuilds to NeuralDocumentModelQuota.
  • In class DocumentClassifierDetails, renamed property ApiVersion to ServiceVersion.
  • Renamed struct FontStyle to DocumentFontStyle.
  • Renamed struct FontWeight to DocumentFontWeight.
  • Renamed class QuotaDetails to ResourceQuotaDetails.

Bugs Fixed

  • Fixed a bug where calling the GetResourceDetails API while targeting service version 2022-08-31 would throw an ArgumentNullException.
Commits
  • 11736d0 Preparing for Storage WebJobs Extension Release for Blobs (#38123)
  • ce1d633 [FormRecognizer] Updated docs for 4.1.0 + final architect feedback (#38092)
  • fa1648a Update Azure Quantum Jobs readme, tests and samples to use Quantum Computing ...
  • f178f4a Delete CI and Tests yml files for deprecated T1 library (#38140)
  • e912f82 Don't pass cancelled token to TryExecute when draining (#38063)
  • 0dd488b [Communication] Migrated recordings to the assets repo (#37803)
  • d948c8d Used ScheduledPurgeDate for both KV, MHSM (#38124)
  • a058b17 [Storage] [Webjobs] Adding MaxDequeueCount to Format() (#37965)
  • ced5079 Increment package version after release of Azure.Monitor.OpenTelemetry.Export...
  • c0e88b6 [AppConfig] Update mocking guidance instructions (#38118)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Azure.AI.FormRecognizer&package-manager=nuget&previous-version=4.0.0&new-version=4.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- webapi/CopilotChatWebApi.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index 861bc9799..ffbbc1d53 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -10,7 +10,7 @@ - + From 1bcb11daa05b555d83e7b6198a4191afcefa3d98 Mon Sep 17 00:00:00 2001 From: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com> Date: Mon, 14 Aug 2023 13:18:41 -0700 Subject: [PATCH 12/18] Functional improvements + bug squashing (#153) ### Motivation and Context A variety of functional improvements, including: - Adding supplement to ExternalInformation section of plan to help provide model more guidance. - Adding tabs in prompt dialog to support view of raw rendered prompt content - Fixing a bug to support .md file import - In formatted prompt, added explicit message to indicate no relevant document memories were used in rendered prompt - Note "Coming soon" for planner token usage - Frontload custom plugins when they're added - Align Login View - Header corner items won't show on app launch up pages (i.e., backend probe page) #### Description + Screenshots New login view ![Screenshot 2023-08-11 at 1 43 08 PM](https://github.com/microsoft/chat-copilot/assets/125500434/49fd63f5-73d0-4804-bda5-0bdeea29caf6) Update prompt dialog with tabs ![Screenshot 2023-08-11 at 1 55 32 PM](https://github.com/microsoft/chat-copilot/assets/125500434/474306e0-77a8-4d41-9c1d-27cf638a9f3f) Support .md files ![Screenshot 2023-08-11 at 1 56 09 PM](https://github.com/microsoft/chat-copilot/assets/125500434/aff476f8-61b7-4699-9201-fc07623362c6) ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations ~~- [ ] All unit tests pass, and I have added new tests where possible~~ - [x] I didn't break anyone :smile: --- .../Controllers/DocumentImportController.cs | 3 +- webapi/Models/Response/BotResponsePrompt.cs | 4 +-- .../ChatSkills/ExternalInformationSkill.cs | 13 ++++--- webapi/appsettings.json | 15 ++++---- webapp/src/App.tsx | 20 ++++++----- .../chat/prompt-dialog/PromptDialog.tsx | 35 +++++++++++++++++-- webapp/src/components/chat/tabs/PlansTab.tsx | 10 +++++- .../components/header/UserSettingsMenu.tsx | 1 + .../plugin-wizard/PluginWizard.tsx | 6 +++- .../token-usage/TokenUsageGraph.tsx | 7 ++-- .../token-usage/TokenUsageLegendItem.tsx | 4 +++ webapp/src/components/views/Login.tsx | 4 ++- webapp/src/libs/models/BotResponsePrompt.ts | 3 ++ .../redux/features/plugins/pluginsSlice.ts | 2 +- 14 files changed, 92 insertions(+), 35 deletions(-) diff --git a/webapi/Controllers/DocumentImportController.cs b/webapi/Controllers/DocumentImportController.cs index ab92ffecd..e5a352f0d 100644 --- a/webapi/Controllers/DocumentImportController.cs +++ b/webapi/Controllers/DocumentImportController.cs @@ -271,6 +271,7 @@ private async Task ValidateDocumentImportFormAsync(DocumentImportForm documentIm { case SupportedFileType.Txt: case SupportedFileType.Pdf: + case SupportedFileType.Md: break; case SupportedFileType.Jpg: case SupportedFileType.Png: @@ -461,7 +462,7 @@ private string GetReadableByteString(long bytes) private SupportedFileType GetFileType(string fileName) { string extension = Path.GetExtension(fileName).ToUpperInvariant(); - return extension switch + return extension.ToUpperInvariant() switch { ".TXT" => SupportedFileType.Txt, ".MD" => SupportedFileType.Md, diff --git a/webapi/Models/Response/BotResponsePrompt.cs b/webapi/Models/Response/BotResponsePrompt.cs index 44b87c8a5..2dbf6ceec 100644 --- a/webapi/Models/Response/BotResponsePrompt.cs +++ b/webapi/Models/Response/BotResponsePrompt.cs @@ -52,9 +52,9 @@ public class BotResponsePrompt public string SystemChatContinuation { get; set; } = string.Empty; /// - /// Raw content of the prompt. Used to pass rendered prompt around ChatSkill. + /// Raw content of the rendered prompt. /// - [JsonIgnore] + [JsonPropertyName("rawContent")] public string RawContent { get; set; } = string.Empty; public BotResponsePrompt( diff --git a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs index bfa23b211..6d6d64ef2 100644 --- a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs +++ b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs @@ -45,7 +45,12 @@ public class ExternalInformationSkill /// /// Preamble to add to the related information text. /// - private const string PromptPreamble = "[RELATED START]"; + private const string PromptPreamble = "[SOURCE START]"; + + /// + /// Supplement to help guide model in using data. + /// + private const string PromptSupplement = "This is the result of invoking the functions listed after \"PLUGINS USED:\" to retrieve additional information outside of the data you were trained on. You can use this data to help answer the user's query."; /// /// Header to indicate plan results. @@ -55,7 +60,7 @@ public class ExternalInformationSkill /// /// Postamble to add to the related information text. /// - private const string PromptPostamble = "[RELATED END]"; + private const string PromptPostamble = "[SOURCE END]"; /// /// Create a new instance of ExternalInformationSkill. @@ -109,7 +114,7 @@ public async Task AcquireExternalInformationAsync( // Invoke plan newPlanContext = await plan.InvokeAsync(newPlanContext); - var functionsUsed = $"FUNCTIONS EXECUTED: {string.Join("; ", this.GetPlanSteps(plan))}."; + var functionsUsed = $"PLUGINS USED: {string.Join("; ", this.GetPlanSteps(plan))}."; int tokenLimit = int.Parse(context.Variables["tokenLimit"], new NumberFormatInfo()) - @@ -131,7 +136,7 @@ public async Task AcquireExternalInformationAsync( planResult = newPlanContext.Variables.Input; } - return $"{PromptPreamble}\n{functionsUsed}\n{ResultHeader}{planResult.Trim()}\n{PromptPostamble}\n"; + return $"{PromptPreamble}\n{PromptSupplement}\n{functionsUsed}\n{ResultHeader}{planResult.Trim()}\n{PromptPostamble}\n"; } else { diff --git a/webapi/appsettings.json b/webapi/appsettings.json index c4b65326d..5e671bf6f 100644 --- a/webapi/appsettings.json +++ b/webapi/appsettings.json @@ -23,7 +23,7 @@ // Default AI service configuration for generating AI responses and embeddings from the user's input. // https://platform.openai.com/docs/guides/chat // To use Azure OpenAI as the AI completion service: - // - Set "Type" to "AzureOpenAI" + // - Set "Type" to "AzureOpenAI" // - Set "Endpoint" to the endpoint of your Azure OpenAI instance (e.g., "https://contoso.openai.azure.com") // - Set "Key" using dotnet's user secrets (see above) // (i.e. dotnet user-secrets set "AIService:Key" "MY_AZURE_OPENAI_KEY") @@ -53,12 +53,12 @@ // - Set Planner:Type to "Sequential" to enable the multi-step SequentialPlanner // Note: SequentialPlanner works best with `gpt-4`. See the "Enabling Sequential Planner" section in webapi/README.md for configuration instructions. // - Set Planner:Type to "Stepwise" to enable MRKL style planning - // - Set Planner:RelevancyThreshold to a decimal between 0 and 1.0. + // - Set Planner:RelevancyThreshold to a decimal between 0 and 1.0. // "Planner": { "Type": "Sequential", // The minimum relevancy score for a function to be considered. - // Set RelevancyThreshold to a value between 0 and 1 if using the SequentialPlanner or Stepwise planner with gpt-3.5-turbo. + // Set RelevancyThreshold to a value between 0 and 1 if using the SequentialPlanner or Stepwise planner with gpt-3.5-turbo. // Ignored when Planner:Type is "Action" "RelevancyThreshold": "0.25", // Whether to allow missing functions in the plan on creation then sanitize output. Functions are considered missing if they're not available in the planner's kernel's context. @@ -170,7 +170,7 @@ // OCR support is used for allowing end users to upload images containing text in addition to text based documents. // - Supported Types are "none", "azureformrecognizer", "tesseract". // - When using Tesseract OCR Support (In order to upload image file formats such as png, jpg and tiff) - // - Obtain language data files here: https://github.com/tesseract-ocr/tessdata . + // - Obtain language data files here: https://github.com/tesseract-ocr/tessdata . // - Add these files to your `data` folder or the path specified in the "FilePath" property and set the "Copy to Output Directory" value to "Copy if newer". // - When using Azure Form Recognizer OCR Support // - Set "OcrSupport:AzureFormRecognizer:Key" using dotnet's user secrets (see above) @@ -217,10 +217,7 @@ // Filter for hostnames app can bind to "AllowedHosts": "*", // CORS - "AllowedOrigins": [ - "http://localhost:3000", - "https://localhost:3000" - ], + "AllowedOrigins": ["http://localhost:3000", "https://localhost:3000"], // The schema information for a serialized bot that is supported by this application. "BotSchema": { "Name": "CopilotChat", @@ -250,4 +247,4 @@ // (i.e. dotnet user-secrets set "APPLICATIONINSIGHTS_CONNECTION_STRING" "MY_APPINS_CONNSTRING") // "APPLICATIONINSIGHTS_CONNECTION_STRING": null -} \ No newline at end of file +} diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index c89bffefe..68036d4c4 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -129,16 +129,18 @@ const App: FC = () => {
Chat Copilot -
-
- - { - setAppState(AppState.SigningOut); - }} - /> + {appState > AppState.SettingUserInfo && ( +
+
+ + { + setAppState(AppState.SigningOut); + }} + /> +
-
+ )}
{appState === AppState.ProbeForBackend && ( = ({ message }) => { const classes = useClasses(); const dialogClasses = useDialogClasses(); + const [selectedTab, setSelectedTab] = React.useState('formatted'); + const onTabSelect: SelectTabEventHandler = (_event, data) => { + setSelectedTab(data.value); + }; + let prompt: string | BotResponsePrompt; try { prompt = JSON.parse(message.prompt ?? '{}') as BotResponsePrompt; } catch (e) { prompt = message.prompt ?? ''; } + let promptDetails; if (typeof prompt === 'string') { - promptDetails = prompt.split('\n').map((paragraph, idx) =>

{paragraph}

); + promptDetails = formatParagraphTextContent(prompt); } else { promptDetails = Object.entries(prompt).map(([key, value]) => { const isStepwiseThoughtProcess = Constants.STEPWISE_RESULT_NOT_FOUND_REGEX.test(value as string); - return value ? ( + if ( + key === 'chatMemories' && + value && + !(value as string).includes('User has also shared some document snippets:') + ) { + value += '\nNo relevant document memories.'; + } + return value && key !== 'rawContent' ? (
{PromptSectionsNameMap[key]} {isStepwiseThoughtProcess ? ( @@ -84,7 +101,19 @@ export const PromptDialog: React.FC = ({ message }) => { Prompt - {promptDetails} + {message.prompt && ( + + + Formatted + + + Raw Content + + + )} + {selectedTab === 'formatted' && promptDetails} + {selectedTab === 'rawContent' && + formatParagraphTextContent((prompt as BotResponsePrompt).rawContent)}
[JsonPropertyName("externalInformation")] - public string ExternalInformation { get; set; } = string.Empty; + public SemanticDependency ExternalInformation { get; set; } /// /// Most recent messages from chat history. @@ -65,7 +65,7 @@ public BotResponsePrompt( string userIntent, string chatMemories, string documentMemories, - string externalInformation, + SemanticDependency externalInformation, string chatHistory, string systemChatContinuation ) diff --git a/webapi/Models/Response/SemanticDependencies.cs b/webapi/Models/Response/SemanticDependencies.cs new file mode 100644 index 000000000..a65bae5d3 --- /dev/null +++ b/webapi/Models/Response/SemanticDependencies.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Text.Json.Serialization; + +namespace CopilotChat.WebApi.Models.Response; + +/// +/// Information about semantic dependencies of the prompt. +/// +public class SemanticDependency +{ + /// + /// Result of the dependency. This is the output that's injected into the prompt. + /// + [JsonPropertyName("result")] + public string Result { get; set; } = string.Empty; + + /// + /// Context of the dependency. This can be either the prompt template or planner details. + /// + [JsonPropertyName("context")] + public T? Context { get; set; } = default; + + public SemanticDependency(string result, T? context = default) + { + this.Result = result; + this.Context = context; + } +} diff --git a/webapi/Models/Response/StepwiseThoughtProcess.cs b/webapi/Models/Response/StepwiseThoughtProcess.cs new file mode 100644 index 000000000..360d53e9d --- /dev/null +++ b/webapi/Models/Response/StepwiseThoughtProcess.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Text.Json.Serialization; + +namespace CopilotChat.WebApi.Models.Response; + +/// +/// Information about a pass through stepwise planner. +/// +public class StepwiseThoughtProcess +{ + /// + /// Steps taken execution stat. + /// + [JsonPropertyName("stepsTaken")] + public string StepsTaken { get; set; } = string.Empty; + + /// + /// Time taken to fulfil the goal. + /// Format: hh:mm:ss + /// + [JsonPropertyName("timeTaken")] + public string TimeTaken { get; set; } = string.Empty; + + /// + /// Skills used execution stat. + /// + [JsonPropertyName("skillsUsed")] + public string SkillsUsed { get; set; } = string.Empty; + + /// + /// Planner type. + /// + [JsonPropertyName("plannerType")] + public PlanType PlannerType { get; set; } = PlanType.Stepwise; + + public StepwiseThoughtProcess(string stepsTaken, string timeTaken, string skillsUsed) + { + this.StepsTaken = stepsTaken; + this.TimeTaken = timeTaken; + this.SkillsUsed = skillsUsed; + } +} diff --git a/webapi/Skills/ChatSkills/ChatSkill.cs b/webapi/Skills/ChatSkills/ChatSkill.cs index 6d0f8729e..d06485ef0 100644 --- a/webapi/Skills/ChatSkills/ChatSkill.cs +++ b/webapi/Skills/ChatSkills/ChatSkill.cs @@ -347,6 +347,13 @@ private async Task GetChatResponseAsync(string chatId, string userI var planResult = await this.AcquireExternalInformationAsync(chatContext, userIntent, externalInformationTokenLimit); chatContext.ThrowIfFailed(); + // Extract additional details about planner execution in chat context + // TODO: [Issue #150, sk#2106] Accommodate different planner contexts once core team finishes work to return prompt and token usage. + var plannerDetails = new SemanticDependency( + planResult, + this._externalInformationSkill.StepwiseThoughtProcess + ); + // If plan is suggested, send back to user for approval before running var proposedPlan = this._externalInformationSkill.ProposedPlan; if (proposedPlan != null) @@ -403,7 +410,7 @@ private async Task GetChatResponseAsync(string chatId, string userI // Need to extract this from the rendered prompt because Time and Date are calculated during render var systemChatContinuation = Regex.Match(renderedPrompt, PromptsOptions.SYSTEM_CHAT_CONTINUATION_REGEX).Value; - var promptView = new BotResponsePrompt(renderedPrompt, this._promptOptions.SystemDescription, this._promptOptions.SystemResponse, audience, userIntent, chatMemories, documentMemories, planResult, chatHistory, systemChatContinuation); + var promptView = new BotResponsePrompt(renderedPrompt, this._promptOptions.SystemDescription, this._promptOptions.SystemResponse, audience, userIntent, chatMemories, documentMemories, plannerDetails, chatHistory, systemChatContinuation); // Calculate token usage of prompt template chatContext.Variables.Set(TokenUtilities.GetFunctionKey(chatContext.Logger, "SystemMetaPrompt")!, TokenUtilities.TokenCount(renderedPrompt).ToString(CultureInfo.InvariantCulture)); diff --git a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs index 6d6d64ef2..9d230765b 100644 --- a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs +++ b/webapi/Skills/ChatSkills/ExternalInformationSkill.cs @@ -42,6 +42,11 @@ public class ExternalInformationSkill /// public ProposedPlan? ProposedPlan { get; private set; } + /// + /// Stepwise thought process to return for view. + /// + public StepwiseThoughtProcess? StepwiseThoughtProcess { get; private set; } + /// /// Preamble to add to the related information text. /// @@ -94,9 +99,13 @@ public async Task AcquireExternalInformationAsync( var goal = $"Given the following context, accomplish the user intent.\nContext:\n{contextString}\nUser Intent:{userIntent}"; if (this._planner.PlannerOptions?.Type == PlanType.Stepwise) { - var newPlanContext = context.Clone(); - newPlanContext = await this._planner.RunStepwisePlannerAsync(goal, context); - return $"{PromptPreamble}\n{newPlanContext.Variables.Input.Trim()}\n{PromptPostamble}\n"; + var plannerContext = context.Clone(); + plannerContext = await this._planner.RunStepwisePlannerAsync(goal, context); + this.StepwiseThoughtProcess = new StepwiseThoughtProcess( + plannerContext.Variables["stepsTaken"], + plannerContext.Variables["timeTaken"], + plannerContext.Variables["skillCount"]); + return $"{PromptPreamble}\n{plannerContext.Variables.Input.Trim()}\n{PromptPostamble}\n"; } // Check if plan exists in ask's context variables. diff --git a/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx b/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx index bec893354..731598a26 100644 --- a/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx +++ b/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx @@ -23,13 +23,14 @@ import { } from '@fluentui/react-components'; import { Info16Regular } from '@fluentui/react-icons'; import React from 'react'; -import { Constants } from '../../../Constants'; -import { BotResponsePrompt, PromptSectionsNameMap } from '../../../libs/models/BotResponsePrompt'; +import { BotResponsePrompt, DependencyDetails, PromptSectionsNameMap } from '../../../libs/models/BotResponsePrompt'; import { IChatMessage } from '../../../libs/models/ChatMessage'; +import { PlanType } from '../../../libs/models/Plan'; +import { StepwiseThoughtProcess } from '../../../libs/models/StepwiseThoughtProcess'; import { useDialogClasses } from '../../../styles'; import { TokenUsageGraph } from '../../token-usage/TokenUsageGraph'; import { formatParagraphTextContent } from '../../utils/TextUtils'; -import { StepwiseThoughtProcess } from './stepwise-planner/StepwiseThoughtProcess'; +import { StepwiseThoughtProcessView } from './stepwise-planner/StepwiseThoughtProcessView'; const useClasses = makeStyles({ prompt: { @@ -68,7 +69,20 @@ export const PromptDialog: React.FC = ({ message }) => { promptDetails = formatParagraphTextContent(prompt); } else { promptDetails = Object.entries(prompt).map(([key, value]) => { - const isStepwiseThoughtProcess = Constants.STEPWISE_RESULT_NOT_FOUND_REGEX.test(value as string); + let isStepwiseThoughtProcess = false; + if (key === 'externalInformation') { + const information = value as DependencyDetails; + if (information.context) { + // TODO: [Issue #150, sk#2106] Accommodate different planner contexts once core team finishes work to return prompt and token usage. + const details = information.context as StepwiseThoughtProcess; + isStepwiseThoughtProcess = details.plannerType === PlanType.Stepwise; + } + + if (!isStepwiseThoughtProcess) { + value = information.result; + } + } + if ( key === 'chatMemories' && value && @@ -76,11 +90,12 @@ export const PromptDialog: React.FC = ({ message }) => { ) { value += '\nNo relevant document memories.'; } + return value && key !== 'rawContent' ? (
{PromptSectionsNameMap[key]} {isStepwiseThoughtProcess ? ( - + ) : ( formatParagraphTextContent(value as string) )} diff --git a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseStepView.tsx b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseStepView.tsx index 160526939..aa478f5c1 100644 --- a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseStepView.tsx +++ b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseStepView.tsx @@ -10,13 +10,13 @@ import { import { StepwiseStep } from '../../../../libs/models/StepwiseStep'; import { formatParagraphTextContent } from '../../../utils/TextUtils'; -const useClasses = makeStyles({ +export const useStepClasses = makeStyles({ root: { display: 'flex', ...shorthands.gap(tokens.spacingHorizontalM), }, accordionItem: { - width: '99%', + width: '95%', }, header: { width: '100%', @@ -35,18 +35,20 @@ interface IStepwiseStepViewProps { } export const StepwiseStepView: React.FC = ({ step, index }) => { - const classes = useClasses(); + const classes = useStepClasses(); let header = `[OBSERVATION] ${step.observation}`; let details: string | undefined; - if (step.thought) { + if (step.thought || step.final_answer) { const thoughtRegEx = /\[(THOUGHT|QUESTION|ACTION)](\s*(.*))*/g; - let thought = step.thought.match(thoughtRegEx)?.[0] ?? `[THOUGHT] ${step.thought}`; + let thought = step.final_answer + ? `[FINAL ANSWER] ${step.final_answer}` + : step.thought.match(thoughtRegEx)?.[0] ?? `[THOUGHT] ${step.thought}`; - // Only show the first sentence of the thought in the header. - // Show the rest as details. - const firstSentenceIndex = thought.indexOf('. '); + // Only show the first sentence of the thought in the header. Show the rest as details. + // Match the first period or colon followed by a non-digit or non-letter + const firstSentenceIndex = thought.search(/(\.|:)([^a-z\d]|$)/); if (firstSentenceIndex > 0) { details = thought.substring(firstSentenceIndex + 2); thought = thought.substring(0, firstSentenceIndex + 1); diff --git a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcess.tsx b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcess.tsx deleted file mode 100644 index 709f20d64..000000000 --- a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcess.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Accordion, Body1, makeStyles, mergeClasses, shorthands, tokens } from '@fluentui/react-components'; -import { Constants } from '../../../../Constants'; -import { StepwiseStep } from '../../../../libs/models/StepwiseStep'; -import { StepwiseStepView } from './StepwiseStepView'; - -const useClasses = makeStyles({ - root: { - display: 'flex', - flexDirection: 'column', - ...shorthands.gap(tokens.spacingHorizontalSNudge), - }, - header: { - paddingTop: tokens.spacingVerticalS, - }, -}); - -interface IStepwiseThoughtProcessProps { - stepwiseResult: string; -} - -export const StepwiseThoughtProcess: React.FC = ({ stepwiseResult }) => { - const classes = useClasses(); - - const matches = stepwiseResult.matchAll(Constants.STEPWISE_RESULT_NOT_FOUND_REGEX); - const matchGroups = Array.from(matches); - if (matchGroups.length > 0) { - const steps = JSON.parse(matchGroups[0][2]) as StepwiseStep[]; - return ( -
- {matchGroups[0][1]} - [THOUGHT PROCESS] - - {steps.map((step, index) => { - return ; - })} - -
- ); - } - - return; -}; diff --git a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx new file mode 100644 index 000000000..6196736ee --- /dev/null +++ b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx @@ -0,0 +1,84 @@ +import { + Accordion, + AccordionHeader, + Body1, + Body1Strong, + makeStyles, + mergeClasses, + shorthands, + tokens, +} from '@fluentui/react-components'; +import { useState } from 'react'; +import { Constants } from '../../../../Constants'; +import { DependencyDetails } from '../../../../libs/models/BotResponsePrompt'; +import { StepwiseStep } from '../../../../libs/models/StepwiseStep'; +import { StepwiseThoughtProcess } from '../../../../libs/models/StepwiseThoughtProcess'; +import { formatParagraphTextContent } from '../../../utils/TextUtils'; +import { StepwiseStepView, useStepClasses } from './StepwiseStepView'; + +const useClasses = makeStyles({ + root: { + display: 'flex', + flexDirection: 'column', + ...shorthands.gap(tokens.spacingHorizontalSNudge), + paddingTop: tokens.spacingVerticalS, + paddingBottom: tokens.spacingVerticalS, + }, +}); + +interface IStepwiseThoughtProcessViewProps { + thoughtProcess: DependencyDetails; +} + +export const StepwiseThoughtProcessView: React.FC = ({ thoughtProcess }) => { + const classes = useClasses(); + const stepClasses = useStepClasses(); + const stepwiseDetails = thoughtProcess.context as StepwiseThoughtProcess; + const steps = JSON.parse(stepwiseDetails.stepsTaken) as StepwiseStep[]; + + const testResultNotFound = thoughtProcess.result.matchAll(Constants.STEPWISE_RESULT_NOT_FOUND_REGEX); + const matchGroups = Array.from(testResultNotFound); + const resultNotFound = matchGroups.length > 0; + if (resultNotFound) { + // Extract result not found message. The rest is the same as stepsTaken. + thoughtProcess.result = matchGroups[0][1]; + } + + const [showthoughtProcess, setShowThoughtProcess] = useState(resultNotFound); + + return ( +
+ {formatParagraphTextContent(thoughtProcess.result)} + {!resultNotFound && ( + { + setShowThoughtProcess(!showthoughtProcess); + }} + expandIconPosition="end" + className={stepClasses.header} + > + Explore how the stepwise planner reached this result! Click here to show the steps and logic. + + )} + {showthoughtProcess && ( + <> + Time Taken: + {stepwiseDetails.timeTaken} + Plugins Used: + {!stepwiseDetails.skillsUsed.startsWith('0') ? stepwiseDetails.skillsUsed : 'None'} + + )} + {(resultNotFound || showthoughtProcess) && ( + <> + {Steps taken:} + [THOUGHT PROCESS] + + {steps.map((step: StepwiseStep, index: number) => { + return ; + })} + + + )} +
+ ); +}; diff --git a/webapp/src/components/utils/TextUtils.tsx b/webapp/src/components/utils/TextUtils.tsx index ec986de25..37d824d29 100644 --- a/webapp/src/components/utils/TextUtils.tsx +++ b/webapp/src/components/utils/TextUtils.tsx @@ -74,6 +74,7 @@ export function formatChatTextContent(messageContent: string) { */ export function formatParagraphTextContent(messageContent: string) { messageContent = messageContent.replaceAll('\r\n', '\n\r'); + return ( {messageContent.split('\n').map((paragraph, idx) => ( @@ -85,7 +86,9 @@ export function formatParagraphTextContent(messageContent: string) { display: 'flex', marginLeft: tokens.spacingHorizontalL, } - : undefined + : { + overflowWrap: 'anywhere', + } } > {paragraph} diff --git a/webapp/src/libs/models/BotResponsePrompt.ts b/webapp/src/libs/models/BotResponsePrompt.ts index ac3956d45..16aedbd2d 100644 --- a/webapp/src/libs/models/BotResponsePrompt.ts +++ b/webapp/src/libs/models/BotResponsePrompt.ts @@ -1,3 +1,5 @@ +import { StepwiseThoughtProcess } from './StepwiseThoughtProcess'; + // The final prompt sent to generate bot response. export interface BotResponsePrompt { // The system persona of the chat. @@ -34,3 +36,12 @@ export const PromptSectionsNameMap: Record = { chatHistory: 'Chat History', systemChatContinuation: 'System Chat Continuation', }; + +// Information about semantic dependencies of the prompt. +export interface DependencyDetails { + // Context of the dependency. This can be either the prompt template or planner details. + context: string | StepwiseThoughtProcess; + + // Result of the dependency. This is the output that's injected into the prompt. + result: string; +} diff --git a/webapp/src/libs/models/Plan.ts b/webapp/src/libs/models/Plan.ts index 0b91f9ebc..7e53d22ab 100644 --- a/webapp/src/libs/models/Plan.ts +++ b/webapp/src/libs/models/Plan.ts @@ -15,4 +15,5 @@ export enum PlanState { export enum PlanType { Action, // single-step Sequential, // multi-step + Stepwise, // MRKL style planning } diff --git a/webapp/src/libs/models/StepwiseThoughtProcess.ts b/webapp/src/libs/models/StepwiseThoughtProcess.ts new file mode 100644 index 000000000..8290cb794 --- /dev/null +++ b/webapp/src/libs/models/StepwiseThoughtProcess.ts @@ -0,0 +1,16 @@ +import { PlanType } from './Plan'; + +// Information about a pass through stepwise planner. +export interface StepwiseThoughtProcess { + // Steps taken execution stat. + stepsTaken: string; + + // Time taken to fulfil the goal. + timeTaken: string; + + // Skills used execution stat. + skillsUsed: string; + + // Planner type. + plannerType: PlanType; +} From 8edfcccf84037d9fa9408a958699cc8a2f9bee4c Mon Sep 17 00:00:00 2001 From: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:22:02 -0700 Subject: [PATCH 14/18] Handling unable to create plan error (#176) ### Motivation and Context Planner will return an error with `Not possible to create plan for goal with available functions` in the body if it can't form a plan with the available functions. This PR handles that cases as a non-error and moves forward with regular bot response generation ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations ~~- [ ] All unit tests pass, and I have added new tests where possible~~ - [x] I didn't break anyone :smile: --- .../Skills/ChatSkills/CopilotChatPlanner.cs | 38 +++++++++++-------- .../chat/prompt-dialog/PromptDialog.tsx | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs b/webapi/Skills/ChatSkills/CopilotChatPlanner.cs index 4841e0d55..6e2eb72cd 100644 --- a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs +++ b/webapi/Skills/ChatSkills/CopilotChatPlanner.cs @@ -84,22 +84,30 @@ public async Task CreatePlanAsync(string goal, ILogger logger) Plan plan; - switch (this._plannerOptions?.Type) + try { - case PlanType.Sequential: - plan = await new SequentialPlanner( - this.Kernel, - new SequentialPlannerConfig - { - RelevancyThreshold = this._plannerOptions?.RelevancyThreshold, - // Allow plan to be created with missing functions - AllowMissingFunctions = this._plannerOptions?.MissingFunctionError.AllowRetries ?? false - } - ).CreatePlanAsync(goal); - break; - default: - plan = await new ActionPlanner(this.Kernel).CreatePlanAsync(goal); - break; + switch (this._plannerOptions?.Type) + { + case PlanType.Sequential: + plan = await new SequentialPlanner( + this.Kernel, + new SequentialPlannerConfig + { + RelevancyThreshold = this._plannerOptions?.RelevancyThreshold, + // Allow plan to be created with missing functions + AllowMissingFunctions = this._plannerOptions?.MissingFunctionError.AllowRetries ?? false + } + ).CreatePlanAsync(goal); + break; + default: + plan = await new ActionPlanner(this.Kernel).CreatePlanAsync(goal); + break; + } + } + catch (PlanningException e) when (e.ErrorCode == PlanningException.ErrorCodes.CreatePlanError && e.Message.Contains("Not possible to create plan for goal with available functions", StringComparison.InvariantCulture)) + { + // No relevant functions are available - return an empty plan. + return new Plan(goal); } return this._plannerOptions!.MissingFunctionError.AllowRetries ? this.SanitizePlan(plan, plannerFunctionsView, logger) : plan; diff --git a/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx b/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx index 731598a26..aeaea5a0d 100644 --- a/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx +++ b/webapp/src/components/chat/prompt-dialog/PromptDialog.tsx @@ -116,7 +116,7 @@ export const PromptDialog: React.FC = ({ message }) => { Prompt - {message.prompt && ( + {message.prompt && typeof prompt !== 'string' && ( Formatted From da548414c0b593aeeda1ce528782255c4006d9a9 Mon Sep 17 00:00:00 2001 From: Chris <66376200+crickman@users.noreply.github.com> Date: Tue, 15 Aug 2023 11:10:39 -0700 Subject: [PATCH 15/18] Tuned: Document chunking parameters and debug output (customer input) (#178) ### Motivation and Context Responding to customer feedback on: 1. Document memory UX 1. Debug output ### Description - When debugger is attached locally, appliication insight tracing is not written to the debug output. - Larger document chunks with overlap provide a more coherent view of memories. 1000 tokens just isn't that much. **Current:** ![image](https://github.com/microsoft/chat-copilot/assets/66376200/d859b756-3d37-4e2c-8de2-8660b2bb43d3) **Azure AI Playground:** ![image](https://github.com/microsoft/chat-copilot/assets/66376200/48b7b42a-305f-4d5b-9ad8-2822bf475b46) **Tuned:** ![image](https://github.com/microsoft/chat-copilot/assets/66376200/0cf428ad-b502-4294-aa58-10ae75ee55b3) ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone :smile: --- webapi/Controllers/DocumentImportController.cs | 2 +- webapi/Options/DocumentMemoryOptions.cs | 10 +++++----- webapi/Program.cs | 5 ++--- webapi/appsettings.json | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/webapi/Controllers/DocumentImportController.cs b/webapi/Controllers/DocumentImportController.cs index e5a352f0d..9f45d526d 100644 --- a/webapi/Controllers/DocumentImportController.cs +++ b/webapi/Controllers/DocumentImportController.cs @@ -540,7 +540,7 @@ private async Task ParseDocumentContentToMemoryAsync( // Split the document into lines of text and then combine them into paragraphs. // Note that this is only one of many strategies to chunk documents. Feel free to experiment with other strategies. var lines = TextChunker.SplitPlainTextLines(content, this._options.DocumentLineSplitMaxTokens); - var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, this._options.DocumentParagraphSplitMaxLines); + var paragraphs = TextChunker.SplitPlainTextParagraphs(lines, this._options.DocumentChunkMaxTokens, this._options.DocumentLineSplitMaxTokens); // TODO: Perform the save in parallel. for (var i = 0; i < paragraphs.Count; i++) diff --git a/webapi/Options/DocumentMemoryOptions.cs b/webapi/Options/DocumentMemoryOptions.cs index ce0c22426..85630eec7 100644 --- a/webapi/Options/DocumentMemoryOptions.cs +++ b/webapi/Options/DocumentMemoryOptions.cs @@ -24,20 +24,20 @@ public class DocumentMemoryOptions public string ChatDocumentCollectionNamePrefix { get; set; } = "chat-documents-"; /// - /// Gets or sets the maximum number of tokens to use when splitting a document into lines. - /// Default token limits are suggested by OpenAI: + /// Gets or sets the maximum number of tokens to use when splitting a document into "lines". + /// For more details on tokens and how to count them, see: /// https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them /// [Range(0, int.MaxValue)] public int DocumentLineSplitMaxTokens { get; set; } = 30; /// - /// Gets or sets the maximum number of lines to use when combining lines into paragraphs. - /// Default token limits are suggested by OpenAI: + /// Gets or sets the maximum number of tokens to use when splitting documents for embeddings. + /// For more details on tokens and how to count them, see: /// https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them /// [Range(0, int.MaxValue)] - public int DocumentParagraphSplitMaxLines { get; set; } = 100; + public int DocumentChunkMaxTokens { get; set; } = 100; /// /// Maximum size in bytes of a document to be allowed for importing. diff --git a/webapi/Program.cs b/webapi/Program.cs index ec419ff5d..cbb0410d8 100644 --- a/webapi/Program.cs +++ b/webapi/Program.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using CopilotChat.WebApi.Extensions; @@ -56,9 +57,7 @@ public static async Task Main(string[] args) .AddLogging(logBuilder => logBuilder.AddApplicationInsights()) .AddSingleton(); -#if DEBUG - TelemetryDebugWriter.IsTracingDisabled = false; -#endif + TelemetryDebugWriter.IsTracingDisabled = Debugger.IsAttached; // Add in the rest of the services. builder.Services diff --git a/webapi/appsettings.json b/webapi/appsettings.json index 5e671bf6f..21deb3093 100644 --- a/webapi/appsettings.json +++ b/webapi/appsettings.json @@ -153,7 +153,7 @@ // Document import configuration // - Global documents are documents that are shared across all users. // - User documents are documents that are specific to a user. - // - Default token limits are suggested by OpenAI: + // - For more details on tokens and how to count them, see: // https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them // - Prevent large uploads by setting a file size limit (in bytes) as suggested here: // https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-6.0 @@ -161,8 +161,8 @@ "DocumentMemory": { "GlobalDocumentCollectionName": "global-documents", "ChatDocumentCollectionNamePrefix": "chat-documents-", - "DocumentLineSplitMaxTokens": 30, - "DocumentParagraphSplitMaxLines": 100, + "DocumentLineSplitMaxTokens": 72, + "DocumentChunkMaxTokens": 512, "FileSizeLimit": 4000000, "FileCountLimit": 10 }, From 07075ae592720631f142a5bf6872640050253670 Mon Sep 17 00:00:00 2001 From: Kevin BEAUGRAND <9513635+kbeaugrand@users.noreply.github.com> Date: Tue, 15 Aug 2023 20:37:17 +0200 Subject: [PATCH 16/18] Add postgresql memory store (#175) ### Motivation and Context I would like to provide a production-grade PaaS solution to store the vector database. It provides PostgreSQL database support for memory. We can now use Azure Database for PostgreSQL or CosmosDB for PostgreSQL. Fixes #166 ### Description I added configuration support for PostgreSQL. in the kernel initialization. Furthermore I updated the deployment script to support this configuration. > Note: In the deployment scripts, I've added the SqlAdminPassword parameter, which must be supplied during provisioning. I intentionally named it without the PostgreSQL name, as I also worked on implementing SQL Server Memory store in the SK repository. This parameter could be used by both databases during deployment. ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible > Not found test project on the API part ;( - [x] I didn't break anyone :smile: --------- Co-authored-by: Gil LaHaye --- scripts/deploy/deploy-azure.ps1 | 14 ++- scripts/deploy/deploy-azure.sh | 16 ++- scripts/deploy/main.bicep | 89 +++++++++++++ scripts/deploy/main.json | 117 +++++++++++++++++- webapi/CopilotChatWebApi.csproj | 25 ++-- webapi/Extensions/SemanticKernelExtensions.cs | 22 ++++ webapi/Options/MemoryStoreOptions.cs | 13 +- webapi/Options/PostgresOptions.cs | 23 ++++ webapi/appsettings.json | 8 +- 9 files changed, 312 insertions(+), 15 deletions(-) create mode 100644 webapi/Options/PostgresOptions.cs diff --git a/scripts/deploy/deploy-azure.ps1 b/scripts/deploy/deploy-azure.ps1 index dfe421209..4e6e712bf 100644 --- a/scripts/deploy/deploy-azure.ps1 +++ b/scripts/deploy/deploy-azure.ps1 @@ -44,11 +44,15 @@ param( # SKU for the Azure App Service plan $WebAppServiceSku = "B1", - [ValidateSet("Volatile", "AzureCognitiveSearch", "Qdrant")] + [ValidateSet("Volatile", "AzureCognitiveSearch", "Qdrant", "Postgres")] [string] # What method to use to persist embeddings $MemoryStore = "AzureCognitiveSearch", + [SecureString] + # Password for the Postgres database + $SqlAdminPassword = "", + [switch] # Don't deploy Cosmos DB for chat storage - Use volatile memory instead $NoCosmosDb, @@ -87,6 +91,11 @@ if ($AIService -eq "OpenAI" -and !$AIApiKey) { exit 1 } +if ($MemoryStore -eq "Postgres" -and !$SqlAdminPassword) { + Write-Host "When MemoryStore is Postgres, SqlAdminPassword must be set" + exit 1 +} + $jsonConfig = " { `\`"webAppServiceSku`\`": { `\`"value`\`": `\`"$WebAppServiceSku`\`" }, @@ -97,7 +106,8 @@ $jsonConfig = " `\`"deployNewAzureOpenAI`\`": { `\`"value`\`": $(If ($DeployAzureOpenAI) {"true"} Else {"false"}) }, `\`"memoryStore`\`": { `\`"value`\`": `\`"$MemoryStore`\`" }, `\`"deployCosmosDB`\`": { `\`"value`\`": $(If (!($NoCosmosDb)) {"true"} Else {"false"}) }, - `\`"deploySpeechServices`\`": { `\`"value`\`": $(If (!($NoSpeechServices)) {"true"} Else {"false"}) } + `\`"deploySpeechServices`\`": { `\`"value`\`": $(If (!($NoSpeechServices)) {"true"} Else {"false"}) }, + `\`"sqlAdminPassword`\`": { `\`"value`\`": `\`"$(ConvertFrom-SecureString $SqlAdminPassword -AsPlainText)`\`" } } " diff --git a/scripts/deploy/deploy-azure.sh b/scripts/deploy/deploy-azure.sh index fa60aec93..09e704d6b 100755 --- a/scripts/deploy/deploy-azure.sh +++ b/scripts/deploy/deploy-azure.sh @@ -19,7 +19,8 @@ usage() { echo " -wr, --web-app-region WEB_APP_REGION Region to deploy to the static web app into. This must be a region that supports static web apps. (default: \"West US 2\")" echo " -a, --app-service-sku WEB_APP_SVC_SKU SKU for the Azure App Service plan (default: \"B1\")" echo " -ms, --memory-store Method to use to persist embeddings. Valid values are" - echo " \"AzureCognitiveSearch\" (default), \"Qdrant\" and \"Volatile\"" + echo " \"AzureCognitiveSearch\" (default), \"Qdrant\", \"Postgres\" and \"Volatile\"" + echo " -sap, --sql-admin-password Password for the PostgreSQL Server admin user" echo " -nc, --no-cosmos-db Don't deploy Cosmos DB for chat storage - Use volatile memory instead" echo " -ns, --no-speech-services Don't deploy Speech Services to enable speech as chat input" echo " -dd, --debug-deployment Switches on verbose template deployment output" @@ -84,6 +85,11 @@ while [[ $# -gt 0 ]]; do MEMORY_STORE=="$2" shift ;; + -sap|--sql-admin-password) + SQL_ADMIN_PASSWORD="$2" + shift + shift + ;; -nc|--no-cosmos-db) NO_COSMOS_DB=true shift @@ -152,6 +158,13 @@ if [[ "${AI_SERVICE_TYPE,,}" = "openai" ]] && [[ -z "$AI_SERVICE_KEY" ]]; then exit 1 fi +# If MEMORY_STORE is Postges, then SQL_ADMIN_PASSWORD is mandatory +if [[ "${MEMORY_STORE,,}" = "postgres" ]] && [[ -z "$SQL_ADMIN_PASSWORD" ]]; then + echo "When --memory-store is 'Postgres', --sql-admin-password must be set." + usage + exit 1 +fi + # If resource group is not set, then set it to rg-DEPLOYMENT_NAME if [ -z "$RESOURCE_GROUP" ]; then RESOURCE_GROUP="rg-${DEPLOYMENT_NAME}" @@ -187,6 +200,7 @@ JSON_CONFIG=$(cat << EOF "aiEndpoint": { "value": "$([ ! -z "$AI_ENDPOINT" ] && echo "$AI_ENDPOINT")" }, "deployNewAzureOpenAI": { "value": $([ "$NO_NEW_AZURE_OPENAI" = true ] && echo "false" || echo "true") }, "memoryStore": { "value": "$MEMORY_STORE" }, + "sqlAdminPassword": { "value": "$SQL_ADMIN_PASSWORD" }, "deployCosmosDB": { "value": $([ "$NO_COSMOS_DB" = true ] && echo "false" || echo "true") }, "deploySpeechServices": { "value": $([ "$NO_SPEECH_SERVICES" = true ] && echo "false" || echo "true") } } diff --git a/scripts/deploy/main.bicep b/scripts/deploy/main.bicep index 569ebc312..1703d7548 100644 --- a/scripts/deploy/main.bicep +++ b/scripts/deploy/main.bicep @@ -54,6 +54,7 @@ param deployCosmosDB bool = true 'Volatile' 'AzureCognitiveSearch' 'Qdrant' + 'Postgres' ]) param memoryStore string = 'Volatile' @@ -78,6 +79,10 @@ var uniqueName = '${name}-${rgIdHash}' @description('Name of the Azure Storage file share to create') var storageFileShareName = 'aciqdrantshare' +@description('PostgreSQL admin password') +@secure() +param sqlAdminPassword string = newGuid() + resource openAI 'Microsoft.CognitiveServices/accounts@2022-12-01' = if (deployNewAzureOpenAI) { name: 'ai-${uniqueName}' location: location @@ -250,6 +255,10 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { name: 'MemoryStore:AzureCognitiveSearch:Key' value: memoryStore == 'AzureCognitiveSearch' ? azureCognitiveSearch.listAdminKeys().primaryKey : '' } + { + name: 'MemoryStore:Postgres:ConnectionString' + value: memoryStore == 'Postgres' ? 'Host=${postgreServerGroup.properties.serverNames[0].fullyQualifiedDomainName}:5432;Username=citus;Password=${sqlAdminPassword};Database=citus' : '' + } { name: 'AzureSpeech:Region' value: location @@ -501,6 +510,16 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2021-05-01' = { privateLinkServiceNetworkPolicies: 'Enabled' } } + { + name: 'postgresSubnet' + properties: { + addressPrefix: '10.0.3.0/24' + serviceEndpoints: [] + delegations: [] + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + } ] } } @@ -703,6 +722,76 @@ resource memorySourcesContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDataba } } +resource postgreServerGroup 'Microsoft.DBforPostgreSQL/serverGroupsv2@2022-11-08' = if (memoryStore == 'Postgres') { + name: 'pg-${uniqueName}' + location: location + properties: { + postgresqlVersion: '15' + administratorLoginPassword: sqlAdminPassword + enableHa: false + coordinatorVCores: 1 + coordinatorServerEdition: 'BurstableMemoryOptimized' + coordinatorStorageQuotaInMb: 32768 + nodeVCores: 4 + nodeCount: 0 + nodeStorageQuotaInMb: 524288 + nodeEnablePublicIpAccess: false + } +} + +resource postgresDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (memoryStore == 'Postgres') { + name: 'privatelink.postgres.cosmos.azure.com' + location: 'global' +} + +resource postgresPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = if (memoryStore == 'Postgres') { + name: 'pg-${uniqueName}-pe' + location: location + properties: { + subnet: { + id: virtualNetwork.properties.subnets[2].id + } + privateLinkServiceConnections: [ + { + name: 'postgres' + properties: { + privateLinkServiceId: postgreServerGroup.id + groupIds: [ + 'coordinator' + ] + } + } + ] + } +} + +resource postgresVirtualNetworkLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = if (memoryStore == 'Postgres') { + parent: postgresDNSZone + name: 'pg-${uniqueName}-vnl' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: true + } +} + +resource postgresPrivateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-04-01' = if (memoryStore == 'Postgres') { + #disable-next-line use-parent-property + name: '${postgresPrivateEndpoint.name}/default' + properties: { + privateDnsZoneConfigs: [ + { + name: 'postgres' + properties: { + privateDnsZoneId: postgresDNSZone.id + } + } + ] + } +} + resource speechAccount 'Microsoft.CognitiveServices/accounts@2022-12-01' = if (deploySpeechServices) { name: 'cog-${uniqueName}' location: location diff --git a/scripts/deploy/main.json b/scripts/deploy/main.json index 3e27026dd..7b2a045f5 100644 --- a/scripts/deploy/main.json +++ b/scripts/deploy/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.20.4.51522", - "templateHash": "15530074115758293206" + "templateHash": "1330294935556235998" } }, "parameters": { @@ -113,7 +113,8 @@ "allowedValues": [ "Volatile", "AzureCognitiveSearch", - "Qdrant" + "Qdrant", + "Postgres" ], "metadata": { "description": "What method to use to persist embeddings" @@ -146,6 +147,13 @@ "metadata": { "description": "Region for the webapp frontend" } + }, + "sqlAdminPassword": { + "type": "securestring", + "defaultValue": "[newGuid()]", + "metadata": { + "description": "PostgreSQL admin password" + } } }, "variables": { @@ -359,6 +367,10 @@ "name": "MemoryStore:AzureCognitiveSearch:Key", "value": "[if(equals(parameters('memoryStore'), 'AzureCognitiveSearch'), listAdminKeys(resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName'))), '2022-09-01').primaryKey, '')]" }, + { + "name": "MemoryStore:Postgres:ConnectionString", + "value": "[if(equals(parameters('memoryStore'), 'Postgres'), format('Host={0}:5432;Username=citus;Password={1};Database=citus', reference(resourceId('Microsoft.DBforPostgreSQL/serverGroupsv2', format('pg-{0}', variables('uniqueName'))), '2022-11-08').serverNames[0].fullyQualifiedDomainName, parameters('sqlAdminPassword')), '')]" + }, { "name": "AzureSpeech:Region", "value": "[parameters('location')]" @@ -416,6 +428,7 @@ "[resourceId('Microsoft.Search/searchServices', format('acs-{0}', variables('uniqueName')))]", "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(format('cosmos-{0}', variables('uniqueName'))))]", "[resourceId('Microsoft.CognitiveServices/accounts', format('ai-{0}', variables('uniqueName')))]", + "[resourceId('Microsoft.DBforPostgreSQL/serverGroupsv2', format('pg-{0}', variables('uniqueName')))]", "[resourceId('Microsoft.CognitiveServices/accounts', format('cog-{0}', variables('uniqueName')))]" ] }, @@ -636,6 +649,16 @@ "privateEndpointNetworkPolicies": "Disabled", "privateLinkServiceNetworkPolicies": "Enabled" } + }, + { + "name": "postgresSubnet", + "properties": { + "addressPrefix": "10.0.3.0/24", + "serviceEndpoints": [], + "delegations": [], + "privateEndpointNetworkPolicies": "Disabled", + "privateLinkServiceNetworkPolicies": "Enabled" + } } ] }, @@ -878,6 +901,96 @@ "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', toLower(format('cosmos-{0}', variables('uniqueName'))), 'CopilotChat')]" ] }, + { + "condition": "[equals(parameters('memoryStore'), 'Postgres')]", + "type": "Microsoft.DBforPostgreSQL/serverGroupsv2", + "apiVersion": "2022-11-08", + "name": "[format('pg-{0}', variables('uniqueName'))]", + "location": "[parameters('location')]", + "properties": { + "postgresqlVersion": "15", + "administratorLoginPassword": "[parameters('sqlAdminPassword')]", + "enableHa": false, + "coordinatorVCores": 1, + "coordinatorServerEdition": "BurstableMemoryOptimized", + "coordinatorStorageQuotaInMb": 32768, + "nodeVCores": 4, + "nodeCount": 0, + "nodeStorageQuotaInMb": 524288, + "nodeEnablePublicIpAccess": false + } + }, + { + "condition": "[equals(parameters('memoryStore'), 'Postgres')]", + "type": "Microsoft.Network/privateDnsZones", + "apiVersion": "2020-06-01", + "name": "privatelink.postgres.cosmos.azure.com", + "location": "global" + }, + { + "condition": "[equals(parameters('memoryStore'), 'Postgres')]", + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[format('pg-{0}-pe', variables('uniqueName'))]", + "location": "[parameters('location')]", + "properties": { + "subnet": { + "id": "[reference(resourceId('Microsoft.Network/virtualNetworks', format('vnet-{0}', variables('uniqueName'))), '2021-05-01').subnets[2].id]" + }, + "privateLinkServiceConnections": [ + { + "name": "postgres", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.DBforPostgreSQL/serverGroupsv2', format('pg-{0}', variables('uniqueName')))]", + "groupIds": [ + "coordinator" + ] + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.DBforPostgreSQL/serverGroupsv2', format('pg-{0}', variables('uniqueName')))]", + "[resourceId('Microsoft.Network/virtualNetworks', format('vnet-{0}', variables('uniqueName')))]" + ] + }, + { + "condition": "[equals(parameters('memoryStore'), 'Postgres')]", + "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", + "apiVersion": "2020-06-01", + "name": "[format('{0}/{1}', 'privatelink.postgres.cosmos.azure.com', format('pg-{0}-vnl', variables('uniqueName')))]", + "location": "global", + "properties": { + "virtualNetwork": { + "id": "[resourceId('Microsoft.Network/virtualNetworks', format('vnet-{0}', variables('uniqueName')))]" + }, + "registrationEnabled": true + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', 'privatelink.postgres.cosmos.azure.com')]", + "[resourceId('Microsoft.Network/virtualNetworks', format('vnet-{0}', variables('uniqueName')))]" + ] + }, + { + "condition": "[equals(parameters('memoryStore'), 'Postgres')]", + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/default', format('pg-{0}-pe', variables('uniqueName')))]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "postgres", + "properties": { + "privateDnsZoneId": "[resourceId('Microsoft.Network/privateDnsZones', 'privatelink.postgres.cosmos.azure.com')]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateDnsZones', 'privatelink.postgres.cosmos.azure.com')]", + "[resourceId('Microsoft.Network/privateEndpoints', format('pg-{0}-pe', variables('uniqueName')))]" + ] + }, { "condition": "[parameters('deploySpeechServices')]", "type": "Microsoft.CognitiveServices/accounts", diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index ffbbc1d53..8fc3cc647 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -13,13 +13,22 @@ - - - - - - - + + + + + + + + @@ -80,4 +89,4 @@ PreserveNewest - + \ No newline at end of file diff --git a/webapi/Extensions/SemanticKernelExtensions.cs b/webapi/Extensions/SemanticKernelExtensions.cs index 034968784..a71a54689 100644 --- a/webapi/Extensions/SemanticKernelExtensions.cs +++ b/webapi/Extensions/SemanticKernelExtensions.cs @@ -17,11 +17,14 @@ using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding; using Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch; using Microsoft.SemanticKernel.Connectors.Memory.Chroma; +using Microsoft.SemanticKernel.Connectors.Memory.Postgres; using Microsoft.SemanticKernel.Connectors.Memory.Qdrant; using Microsoft.SemanticKernel.Memory; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.Skills.Core; using Microsoft.SemanticKernel.TemplateEngine; +using Npgsql; +using Pgvector.Npgsql; using static CopilotChat.WebApi.Options.MemoryStoreOptions; namespace CopilotChat.WebApi.Extensions; @@ -221,6 +224,25 @@ private static void AddSemanticTextMemory(this IServiceCollection services) }); break; + case MemoryStoreOptions.MemoryStoreType.Postgres: + if (config.Postgres == null) + { + throw new InvalidOperationException("MemoryStore type is Cosmos and Cosmos configuration is null."); + } + + var dataSourceBuilder = new NpgsqlDataSourceBuilder(config.Postgres.ConnectionString); + dataSourceBuilder.UseVector(); + + services.AddSingleton(sp => + { + return new PostgresMemoryStore( + dataSource: dataSourceBuilder.Build(), + vectorSize: config.Postgres.VectorSize + ); + }); + + break; + default: throw new InvalidOperationException($"Invalid 'MemoryStore' type '{config.Type}'."); } diff --git a/webapi/Options/MemoryStoreOptions.cs b/webapi/Options/MemoryStoreOptions.cs index a55da230a..de6b279ca 100644 --- a/webapi/Options/MemoryStoreOptions.cs +++ b/webapi/Options/MemoryStoreOptions.cs @@ -32,7 +32,12 @@ public enum MemoryStoreType /// /// Chroma DB persistent memory store. /// - Chroma + Chroma, + + /// + /// Cosmos DB persistent memory store. + /// + Postgres, } /// @@ -57,4 +62,10 @@ public enum MemoryStoreType /// [RequiredOnPropertyValue(nameof(Type), MemoryStoreType.AzureCognitiveSearch)] public AzureCognitiveSearchOptions? AzureCognitiveSearch { get; set; } + + /// + /// Gets or sets the configuration for the Cosmos memory store. + /// + [RequiredOnPropertyValue(nameof(Type), MemoryStoreType.Postgres)] + public PostgresOptions? Postgres { get; set; } } diff --git a/webapi/Options/PostgresOptions.cs b/webapi/Options/PostgresOptions.cs new file mode 100644 index 000000000..d131a16d1 --- /dev/null +++ b/webapi/Options/PostgresOptions.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.ComponentModel.DataAnnotations; + +namespace CopilotChat.WebApi.Options; + +/// +/// Configuration settings for connecting to Postgres. +/// +public class PostgresOptions +{ + /// + /// Gets or sets the Postgres connection string. + /// + [Required, NotEmptyOrWhitespace] + public string ConnectionString { get; set; } = string.Empty; + + /// + /// Gets or sets the vector size. + /// + [Required, Range(1, int.MaxValue)] + public int VectorSize { get; set; } +} diff --git a/webapi/appsettings.json b/webapi/appsettings.json index 21deb3093..3dde0d808 100644 --- a/webapi/appsettings.json +++ b/webapi/appsettings.json @@ -125,12 +125,14 @@ }, // // Memory stores are used for storing new memories and retrieving semantically similar memories. - // - Supported Types are "volatile", "qdrant", "azurecognitivesearch", or "chroma". + // - Supported Types are "volatile", "qdrant", "azurecognitivesearch", "postgres", or "chroma". // - When using Qdrant or Azure Cognitive Search, see ./README.md for deployment instructions. // - Set "MemoryStore:AzureCognitiveSearch:Key" using dotnet's user secrets (see above) // (i.e. dotnet user-secrets set "MemoryStore:AzureCognitiveSearch:Key" "MY_AZCOGSRCH_KEY") // - Set "MemoryStore:Qdrant:Key" using dotnet's user secrets (see above) if you are using a Qdrant Cloud instance. // (i.e. dotnet user-secrets set "MemoryStore:Qdrant:Key" "MY_QDRANTCLOUD_KEY") + // - Set "MemoryStore:Postgres:ConnectionString" using dotnet's user secrets (see above) if you are using a PostgreSQL database (or CosmosDB for PostgreSQL instance). + // (i.e. dotnet user-secrets set "MemoryStore:Postgres:ConnectionString" "MY_POSTGRES_CONNECTION_STRING") // "MemoryStore": { "Type": "volatile", @@ -147,6 +149,10 @@ "Chroma": { "Host": "http://localhost", "Port": "8000" + }, + "Postgres": { + "VectorSize": 1536 + // "ConnectionString": // dotnet user-secrets set "MemoryStore:Postgres:ConnectionString" "MY_POSTGRES_CONNECTION_STRING" } }, // From 6d5ba70768f3b7d147f0f5bf88fde2ca804f3935 Mon Sep 17 00:00:00 2001 From: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com> Date: Tue, 15 Aug 2023 11:48:12 -0700 Subject: [PATCH 17/18] UX improvements: A11y labels, fixing space input bug, enabling RLFH, etc. (#179) ### Motivation and Context This PR contains the following UX improvements: - Fixes bug where you couldn't enter space when editing chat name on list item - Fixes auto-naming bug to match all datetime syntaxes - Removes inactive field of RLFH - users can now enable this from settings - Adds multiple A11y aria-labels and hover text - Limit privacy alert to users in Microsoft tenant only ### Description Persona component was conflicting with "Space" keydown behavior of ChatListItem, so I removed it. Using the `title` property on the component is sufficient to show hover text: Screenshot 2023-08-15 at 11 22 04 AM Screenshot 2023-08-15 at 11 22 56 AM ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/copilot-chat/blob/main/CONTRIBUTING.md#development-scripts) raises no violations ~~- [ ] All unit tests pass, and I have added new tests where possible~~ - [x] I didn't break anyone :smile: --- webapp/src/App.tsx | 15 +- webapp/src/components/chat/ChatInput.tsx | 6 + webapp/src/components/chat/ChatWindow.tsx | 28 +++- .../chat/chat-history/ChatHistoryItem.tsx | 10 +- .../chat/chat-list/ChatListItem.tsx | 131 +++++++----------- .../chat/chat-list/ChatListSection.tsx | 4 +- .../chat/chat-list/ListItemActions.tsx | 11 +- .../components/chat/persona/PromptEditor.tsx | 5 +- .../components/chat/shared/EditChatName.tsx | 5 +- .../open-api-plugins/PluginGallery.tsx | 2 + webapp/src/redux/features/app/AppState.ts | 9 +- 11 files changed, 123 insertions(+), 103 deletions(-) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 68036d4c4..ddc9c1daf 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -9,10 +9,11 @@ import { UserSettingsMenu } from './components/header/UserSettingsMenu'; import { PluginGallery } from './components/open-api-plugins/PluginGallery'; import { BackendProbe, ChatView, Error, Loading, Login } from './components/views'; import { useChat } from './libs/hooks'; +import { AlertType } from './libs/models/AlertType'; import { useAppDispatch, useAppSelector } from './redux/app/hooks'; import { RootState } from './redux/app/store'; import { FeatureKeys } from './redux/features/app/AppState'; -import { setActiveUserInfo, setServiceOptions } from './redux/features/app/appSlice'; +import { addAlert, setActiveUserInfo, setServiceOptions } from './redux/features/app/appSlice'; import { semanticKernelDarkTheme, semanticKernelLightTheme } from './styles'; export const useClasses = makeStyles({ @@ -81,6 +82,18 @@ const App: FC = () => { username: account.name ?? account.username, }), ); + + // Privacy disclaimer for internal Microsoft users + if (account.username.split('@')[1] === 'microsoft.com') { + dispatch( + addAlert({ + message: + 'By using Chat Copilot, you agree to protect sensitive data, not store it in chat, and allow chat history collection for service improvements. This tool is for internal use only.', + type: AlertType.Info, + }), + ); + } + setAppState(AppState.LoadingChats); } } else { diff --git a/webapp/src/components/chat/ChatInput.tsx b/webapp/src/components/chat/ChatInput.tsx index 14c863555..15c387097 100644 --- a/webapp/src/components/chat/ChatInput.tsx +++ b/webapp/src/components/chat/ChatInput.tsx @@ -183,6 +183,8 @@ export const ChatInput: React.FC = ({ isDraggingOver, onDragLeav