diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 3b4376a87b76..e2612cb2c90c 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -102,6 +102,6 @@ jobs: - name: Archive artifacts ${{ matrix.os }}-${{ matrix.configuration }} uses: actions/upload-artifact@v3 with: - name: drop-${{ matrix.os }}-dotnet${{matrix.dotnet-version}}-${{ matrix.configuration }} + name: drop-${{ matrix.os }}-${{ matrix.configuration }} path: ./out if: ${{ github.event_name == 'push' }} diff --git a/.github/workflows/update-version.sh b/.github/workflows/update-version.sh index 5db3622f6159..12138bd674b8 100755 --- a/.github/workflows/update-version.sh +++ b/.github/workflows/update-version.sh @@ -59,7 +59,7 @@ if [ -z "$buildAndRevisionNumber" ]; then fi propsVersionString=$(cat $propsFile | grep -i ""); -regex="([0-9.]*)<\/Version>" +regex="([0-9.]*)-pre<\/Version>" if [[ $propsVersionString =~ $regex ]]; then propsVersion=${BASH_REMATCH[1]} else diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 49a1dcd2f2ad..7c53ab157a13 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -36,7 +36,7 @@ - + diff --git a/dotnet/nuget/nuget-package.props b/dotnet/nuget/nuget-package.props index 0f7890e54b27..f2290538e3a8 100644 --- a/dotnet/nuget/nuget-package.props +++ b/dotnet/nuget/nuget-package.props @@ -2,8 +2,10 @@ true true - - 0.14 + + 0.14-pre diff --git a/samples/apps/copilot-chat-app/importdocument/ImportDocument.csproj b/samples/apps/copilot-chat-app/importdocument/ImportDocument.csproj index d9445e019707..55ee128d40ab 100644 --- a/samples/apps/copilot-chat-app/importdocument/ImportDocument.csproj +++ b/samples/apps/copilot-chat-app/importdocument/ImportDocument.csproj @@ -22,7 +22,7 @@ - + diff --git a/samples/apps/copilot-chat-app/webapi/Controllers/SemanticKernelController.cs b/samples/apps/copilot-chat-app/webapi/Controllers/SemanticKernelController.cs index b62c43527215..d435009fd508 100644 --- a/samples/apps/copilot-chat-app/webapi/Controllers/SemanticKernelController.cs +++ b/samples/apps/copilot-chat-app/webapi/Controllers/SemanticKernelController.cs @@ -135,7 +135,7 @@ private async Task RegisterPlannerSkillsAsync(CopilotChatPlanner planner, Planne { InnerHandler = new HttpClientHandler() { CheckCertificateRevocationList = true } }; - using HttpClient importHttpClient = new HttpClient(retryHandler, false); + using HttpClient importHttpClient = new(retryHandler, false); importHttpClient.DefaultRequestHeaders.Add("User-Agent", "Microsoft.CopilotChat"); await planner.Kernel.ImportChatGptPluginSkillFromUrlAsync("KlarnaShoppingSkill", new Uri("https://www.klarna.com/.well-known/ai-plugin.json"), importHttpClient); diff --git a/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj b/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj index 97135c143cbf..beb27add2562 100644 --- a/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj +++ b/samples/apps/copilot-chat-app/webapi/CopilotChatApi.csproj @@ -1,4 +1,4 @@ - + $([System.IO.Path]::GetDirectoryName($([MSBuild]::GetPathOfFileAbove('.gitignore', '$(MSBuildThisFileDirectory)')))) @@ -23,14 +23,14 @@ - + - + diff --git a/samples/apps/copilot-chat-app/webapi/Skills/ChatSkill.cs b/samples/apps/copilot-chat-app/webapi/Skills/ChatSkill.cs index c23c599d809b..46e6d0319fef 100644 --- a/samples/apps/copilot-chat-app/webapi/Skills/ChatSkill.cs +++ b/samples/apps/copilot-chat-app/webapi/Skills/ChatSkill.cs @@ -534,23 +534,28 @@ private string OptimizeOpenApiSkillJson(string jsonContent, int tokenLimit, Plan List itemList = new(); - // Summary (List) Object - // To stay within token limits, attempt to truncate the list of results - if (document.RootElement.ValueKind == JsonValueKind.Array) + // Some APIs will return a JSON response with one property key representing an embedded answer. + // Extract this value for further processing + string resultsDescriptor = ""; + + if (document.RootElement.ValueKind == JsonValueKind.Object) { - foreach (JsonElement item in document.RootElement.EnumerateArray()) + int propertyCount = 0; + foreach (JsonProperty property in document.RootElement.EnumerateObject()) { - int itemTokenCount = Utilities.TokenCount(item.ToString()); + propertyCount++; + } - if (jsonTokenLimit - itemTokenCount > 0) - { - itemList.Add(item); - jsonTokenLimit -= itemTokenCount; - } - else - { - break; - } + if (propertyCount == 1) + { + // Save property name for result interpolation + JsonProperty firstProperty = document.RootElement.EnumerateObject().First(); + jsonTokenLimit -= Utilities.TokenCount(firstProperty.Name); + resultsDescriptor = string.Format(CultureInfo.InvariantCulture, "{0}: ", firstProperty.Name); + + // Extract object to be truncated + JsonElement value = firstProperty.Value; + document = JsonDocument.Parse(value.GetRawText()); } } @@ -574,8 +579,28 @@ private string OptimizeOpenApiSkillJson(string jsonContent, int tokenLimit, Plan } } + // Summary (List) Object + // To stay within token limits, attempt to truncate the list of results + if (document.RootElement.ValueKind == JsonValueKind.Array) + { + foreach (JsonElement item in document.RootElement.EnumerateArray()) + { + int itemTokenCount = Utilities.TokenCount(item.ToString()); + + if (jsonTokenLimit - itemTokenCount > 0) + { + itemList.Add(item); + jsonTokenLimit -= itemTokenCount; + } + else + { + break; + } + } + } + return itemList.Count > 0 - ? JsonSerializer.Serialize(itemList) + ? string.Format(CultureInfo.InvariantCulture, "{0}{1}", resultsDescriptor, JsonSerializer.Serialize(itemList)) : string.Format(CultureInfo.InvariantCulture, "JSON response for {0} is too large to be consumed at this time.", lastSkillInvoked); } diff --git a/samples/apps/copilot-chat-app/webapp/src/Constants.ts b/samples/apps/copilot-chat-app/webapp/src/Constants.ts index a37c56f131a5..7e0493a6a575 100644 --- a/samples/apps/copilot-chat-app/webapp/src/Constants.ts +++ b/samples/apps/copilot-chat-app/webapp/src/Constants.ts @@ -39,6 +39,6 @@ export const Constants = { }, // For a list of Microsoft Graph permissions, see https://learn.microsoft.com/en-us/graph/permissions-reference. // Your application registration will need to be granted these permissions in Azure Active Directory. - msGraphScopes: ['Calendars.Read', 'Mail.Read', 'Tasks.ReadWrite', 'User.Read'], + msGraphScopes: ['Calendars.Read', 'Mail.Read', 'Mail.Send', 'Tasks.ReadWrite', 'User.Read'], adoScopes: ['vso.work'], }; diff --git a/samples/apps/copilot-chat-app/webapp/src/components/open-api-plugins/PluginConnector.tsx b/samples/apps/copilot-chat-app/webapp/src/components/open-api-plugins/PluginConnector.tsx index 607e59fb4a76..229d27abedb2 100644 --- a/samples/apps/copilot-chat-app/webapp/src/components/open-api-plugins/PluginConnector.tsx +++ b/samples/apps/copilot-chat-app/webapp/src/components/open-api-plugins/PluginConnector.tsx @@ -66,12 +66,14 @@ export const PluginConnector: React.FC = ({ const classes = useClasses(); const usernameRequired = authRequirements.username; + const emailRequired = authRequirements.email; const passwordRequired = authRequirements.password; const accessTokenRequired = authRequirements.personalAccessToken; const msalRequired = authRequirements.Msal; const oauthRequired = authRequirements.OAuth; const [username, setUsername] = useState(''); + const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [accessToken, setAccessToken] = useState(''); const [apiPropertiesInput, setApiRequirementsInput] = useState(apiProperties); @@ -102,6 +104,7 @@ export const PluginConnector: React.FC = ({ connectPlugin({ plugin: name, username: username, + email: email, password: password, accessToken: accessToken, apiProperties: apiPropertiesInput, @@ -164,7 +167,7 @@ export const PluginConnector: React.FC = ({ )} - {(usernameRequired || accessTokenRequired) && ( + {(usernameRequired || emailRequired || accessTokenRequired) && ( Log in to {name} to continue )} {(msalRequired || oauthRequired) && ( @@ -188,6 +191,20 @@ export const PluginConnector: React.FC = ({ /> )} + {emailRequired && ( + <> + { + setEmail(input.value); + }} + placeholder={`Enter your ${name} email`} + /> + + )} {passwordRequired && ( <> { const { instance, accounts } = useMsal(); const account = useAccount(accounts[0] || {}); const sk = useSemanticKernel(process.env.REACT_APP_BACKEND_URI as string); - const { botProfilePictureIndex } = useAppSelector((state: RootState) => state.conversations); + const { conversations } = useAppSelector((state: RootState) => state.conversations); const connectors = useConnectors(); const botService = new BotService(process.env.REACT_APP_BACKEND_URI as string); @@ -81,10 +80,9 @@ export const useChat = () => { messages: chatMessages, audience: [loggedInUser], botTypingTimestamp: 0, - botProfilePicture: botProfilePictures.at(botProfilePictureIndex) ?? '/assets/bot-icon-1.png', + botProfilePicture: getBotProfilePicture(Object.keys(conversations).length) }; - dispatch(incrementBotProfilePictureIndex()); dispatch(addConversation(newChat)); dispatch(setSelectedConversation(newChat.id)); @@ -173,7 +171,7 @@ export const useChat = () => { ); if (chatSessions.length > 0) { - const conversations: Conversations = {}; + const loadedConversations: Conversations = {}; for (const index in chatSessions) { const chatSession = chatSessions[index]; const chatMessages = await chatService.getChatMessagesAsync( @@ -187,19 +185,17 @@ export const useChat = () => { // so we need to reverse the order for render const orderedMessages = chatMessages.reverse(); - conversations[chatSession.id] = { + loadedConversations[chatSession.id] = { id: chatSession.id, title: chatSession.title, audience: [loggedInUser], messages: orderedMessages, botTypingTimestamp: 0, - botProfilePicture: botProfilePictures[botProfilePictureIndex], + botProfilePicture: getBotProfilePicture(Object.keys(loadedConversations).length), }; - - dispatch(incrementBotProfilePictureIndex()); } - dispatch(setConversations(conversations)); + dispatch(setConversations(loadedConversations)); dispatch(setSelectedConversation(chatSessions[0].id)); } else { // No chats exist, create first chat window @@ -238,6 +234,10 @@ export const useChat = () => { }); }; + const getBotProfilePicture = (index: number) => { + return botProfilePictures[index % botProfilePictures.length]; + }; + return { getAudienceMemberForId, createChat, diff --git a/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/ConversationsState.ts b/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/ConversationsState.ts index 873a77e0fbf2..3764c33467ac 100644 --- a/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/ConversationsState.ts +++ b/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/ConversationsState.ts @@ -10,13 +10,11 @@ export type Conversations = { export interface ConversationsState { conversations: Conversations; selectedId: string; - botProfilePictureIndex: number; } export const initialState: ConversationsState = { conversations: {}, selectedId: '', - botProfilePictureIndex: 0, }; export type UpdateConversationPayload = { diff --git a/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/conversationsSlice.ts b/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/conversationsSlice.ts index d045e663d4f3..d2163a94f893 100644 --- a/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/conversationsSlice.ts +++ b/samples/apps/copilot-chat-app/webapp/src/redux/features/conversations/conversationsSlice.ts @@ -9,9 +9,6 @@ export const conversationsSlice = createSlice({ name: 'conversations', initialState, reducers: { - incrementBotProfilePictureIndex: (state: ConversationsState) => { - state.botProfilePictureIndex = ++state.botProfilePictureIndex % 5; - }, setConversations: (state: ConversationsState, action: PayloadAction) => { state.conversations = action.payload; }, @@ -50,7 +47,6 @@ export const conversationsSlice = createSlice({ }); export const { - incrementBotProfilePictureIndex, setConversations, editConversationTitle, setSelectedConversation, diff --git a/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/PluginsState.ts b/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/PluginsState.ts index a318a518300f..056f04fe6981 100644 --- a/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/PluginsState.ts +++ b/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/PluginsState.ts @@ -24,6 +24,7 @@ export const enum AuthHeaderTags { export type PluginAuthRequirements = { username?: boolean; + email?: boolean; password?: boolean; personalAccessToken?: boolean; OAuth?: boolean; @@ -79,10 +80,10 @@ export const initialState: PluginsState = { Jira: { name: Plugins.Jira, publisher: 'Atlassian', - description: 'Authorize Copilot Chat to post and link with Jira when there are issues.', + description: 'Authorize Copilot Chat to link with Jira and retrieve specific issues by providing the issue key.', enabled: false, authRequirements: { - username: true, + email: true, personalAccessToken: true, helpLink: 'https://developer.atlassian.com/cloud/confluence/basic-auth-for-rest-apis/', }, @@ -90,7 +91,7 @@ export const initialState: PluginsState = { headerTag: AuthHeaderTags.Jira, apiProperties: { 'jira-server-url': { - description: 'base server url', + description: 'server url, i.e. "https://.atlassian.net/rest/api/latest/"', required: true, helpLink: 'https://confluence.atlassian.com/adminjiraserver/configuring-the-base-url-938847830.html', }, @@ -137,6 +138,7 @@ export const initialState: PluginsState = { export type EnablePluginPayload = { plugin: Plugins; username?: string; + email?: string; password?: string; accessToken?: string; apiProperties?: AdditionalApiProperties; diff --git a/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/pluginsSlice.ts b/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/pluginsSlice.ts index 415eae0fbc04..b48e39985cbd 100644 --- a/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/pluginsSlice.ts +++ b/samples/apps/copilot-chat-app/webapp/src/redux/features/plugins/pluginsSlice.ts @@ -17,7 +17,7 @@ export const pluginsState = createSlice({ break; case Plugins.Jira: plugin = state.Jira; - authData = `${action.payload.username}:${action.payload.accessToken}`; + authData = `${action.payload.email}:${action.payload.accessToken}`; break; case Plugins.GitHub: plugin = state.GitHub; diff --git a/samples/apps/hugging-face-http-server/requirements.txt b/samples/apps/hugging-face-http-server/requirements.txt index 4de457de3f07..8c94cf71818d 100644 --- a/samples/apps/hugging-face-http-server/requirements.txt +++ b/samples/apps/hugging-face-http-server/requirements.txt @@ -7,7 +7,7 @@ cryptography==39.0.2 dataclasses==0.6 diffusers==0.2.2 filelock==3.4.1 -Flask==2.0.3 +Flask==2.2.5 huggingface-hub==0.4.0 idna==3.4 importlib-metadata==4.8.3 diff --git a/samples/dotnet/kernel-syntax-examples/KernelSyntaxExamples.csproj b/samples/dotnet/kernel-syntax-examples/KernelSyntaxExamples.csproj index 4f03e8feb86d..953f5350c601 100644 --- a/samples/dotnet/kernel-syntax-examples/KernelSyntaxExamples.csproj +++ b/samples/dotnet/kernel-syntax-examples/KernelSyntaxExamples.csproj @@ -17,7 +17,7 @@ - +