diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts index 255f9d80..78d60756 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts @@ -13,11 +13,13 @@ import { PacWrapper } from '../../../client/pac/PacWrapper'; import { intelligenceAPIAuthentication } from '../../services/AuthenticationProvider'; import { ActiveOrgOutput } from '../../../client/pac/PacTypes'; import { orgChangeErrorEvent, orgChangeEvent } from '../../OrgChangeNotifier'; -import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, NO_PROMPT_MESSAGE, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG } from './PowerPagesChatParticipantConstants'; +import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, GitHubPowerPagesAgentInvoked, GitHubPowerPagesAgentOrgDetails, GitHubPowerPagesAgentOrgDetailsNotFound, GitHubPowerPagesAgentScenario, NO_PROMPT_MESSAGE, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG } from './PowerPagesChatParticipantConstants'; import { ORG_DETAILS_KEY, handleOrgChangeSuccess, initializeOrgDetails } from '../../utilities/OrgHandlerUtils'; import { getComponentInfo, getEndpoint } from './PowerPagesChatParticipantUtils'; import { checkCopilotAvailability, getActiveEditorContent } from '../../utilities/Utils'; import { IIntelligenceAPIEndpointInformation } from '../../services/Interfaces'; +import { v4 as uuidv4 } from 'uuid'; + export class PowerPagesChatParticipant { private static instance: PowerPagesChatParticipant | null = null; private chatParticipant: vscode.ChatParticipant; @@ -27,6 +29,7 @@ export class PowerPagesChatParticipant { private isOrgDetailsInitialized = false; private readonly _disposables: vscode.Disposable[] = []; private cachedEndpoint: IIntelligenceAPIEndpointInformation| null = null; + private powerPagesAgentSessionId: string; private orgID: string | undefined; private orgUrl: string | undefined; @@ -39,6 +42,8 @@ export class PowerPagesChatParticipant { //TODO: Check the icon image this.chatParticipant.iconPath = vscode.Uri.joinPath(context.extensionUri, 'src', 'common', 'chat-participants', 'powerpages', 'assets', 'copilot.png'); + this.powerPagesAgentSessionId = uuidv4(); + this.telemetry = telemetry; this.extensionContext = context; @@ -77,10 +82,13 @@ export class PowerPagesChatParticipant { stream.progress(RESPONSE_AWAITED_MSG) + this.telemetry.sendTelemetryEvent(GitHubPowerPagesAgentInvoked, {sessionId: this.powerPagesAgentSessionId}); + await this.initializeOrgDetails(); if (!this.orgID || !this.environmentID) { stream.markdown(PAC_AUTH_NOT_FOUND); + this.telemetry.sendTelemetryEvent(GitHubPowerPagesAgentOrgDetailsNotFound, {sessionId: this.powerPagesAgentSessionId}); return { metadata: { command: '' @@ -88,11 +96,12 @@ export class PowerPagesChatParticipant { }; } - const intelligenceApiAuthResponse = await intelligenceAPIAuthentication(this.telemetry, '', this.orgID, true); + this.telemetry.sendTelemetryEvent(GitHubPowerPagesAgentOrgDetails, {orgID: this.orgID, environmentID: this.environmentID, sessionId: this.powerPagesAgentSessionId}); + + const intelligenceApiAuthResponse = await intelligenceAPIAuthentication(this.telemetry, this.powerPagesAgentSessionId, this.orgID, true); if (!intelligenceApiAuthResponse) { stream.markdown(AUTHENTICATION_FAILED_MSG); - return { metadata: { command: '', @@ -102,13 +111,12 @@ export class PowerPagesChatParticipant { const intelligenceApiToken = intelligenceApiAuthResponse.accessToken; - const intelligenceAPIEndpointInfo = await getEndpoint(this.orgID, this.environmentID, this.telemetry, this.cachedEndpoint); + const intelligenceAPIEndpointInfo = await getEndpoint(this.orgID, this.environmentID, this.telemetry, this.cachedEndpoint, this.powerPagesAgentSessionId); - const copilotAvailabilityStatus = checkCopilotAvailability(intelligenceAPIEndpointInfo.intelligenceEndpoint, this.orgID, this.telemetry, ''); + const copilotAvailabilityStatus = checkCopilotAvailability(intelligenceAPIEndpointInfo.intelligenceEndpoint, this.orgID, this.telemetry,this.powerPagesAgentSessionId); if (!copilotAvailabilityStatus) { stream.markdown(COPILOT_NOT_AVAILABLE_MSG) - return { metadata: { command: '' @@ -137,9 +145,13 @@ export class PowerPagesChatParticipant { const {activeFileParams} = getActiveEditorContent(); - const {componentInfo, entityName}: IComponentInfo = await getComponentInfo(this.telemetry, this.orgUrl, activeFileParams); + const {componentInfo, entityName}: IComponentInfo = await getComponentInfo(this.telemetry, this.orgUrl, activeFileParams, this.powerPagesAgentSessionId); + + const llmResponse = await sendApiRequest([{ displayText: userPrompt, code: '' }], activeFileParams, this.orgID, intelligenceApiToken, this.powerPagesAgentSessionId, entityName, componentInfo, this.telemetry, intelligenceAPIEndpointInfo.intelligenceEndpoint, intelligenceAPIEndpointInfo.geoName, intelligenceAPIEndpointInfo.crossGeoDataMovementEnabledPPACFlag); + + const scenario = llmResponse.length > 1 ? llmResponse[llmResponse.length - 1] : llmResponse[0].displayText; - const llmResponse = await sendApiRequest([{ displayText: userPrompt, code: '' }], activeFileParams, this.orgID, intelligenceApiToken, '', entityName, componentInfo, this.telemetry, intelligenceAPIEndpointInfo.intelligenceEndpoint, intelligenceAPIEndpointInfo.geoName, intelligenceAPIEndpointInfo.crossGeoDataMovementEnabledPPACFlag); + this.telemetry.sendTelemetryEvent(GitHubPowerPagesAgentScenario, {scenario: scenario, sessionId: this.powerPagesAgentSessionId, orgId: this.orgID, environmentId: this.environmentID}) llmResponse.forEach((response: { displayText: string | vscode.MarkdownString; code: string; }) => { if (response.displayText) { diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts index 536c7b61..b0932bf8 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipantConstants.ts @@ -13,3 +13,9 @@ export const AUTHENTICATION_FAILED_MSG = vscode.l10n.t('Authentication failed. P export const COPILOT_NOT_AVAILABLE_MSG = vscode.l10n.t('Copilot is not available. Please contact your administrator.'); export const PAC_AUTH_NOT_FOUND = vscode.l10n.t('Active auth profile is not found or has expired. Please try again.'); export const SUPPORTED_ENTITIES = [ADX_ENTITYFORM, ADX_ENTITYLIST]; +// Telemetry Event Names +export const GitHubPowerPagesAgentInvoked = 'GitHubPowerPagesAgentInvoked'; +export const GitHubPowerPagesAgentOrgDetails = 'GitHubPowerPagesAgentOrgDetails'; +export const GitHubPowerPagesAgentOrgDetailsNotFound = 'GitHubPowerPagesAgentOrgDetailsNotFound'; +export const GitHubPowerPagesAgentScenario = 'GitHubPowerPagesAgentScenario'; + diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts index 4a71817a..3e57dccc 100644 --- a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts +++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts @@ -19,10 +19,11 @@ export async function getEndpoint( orgID: string, environmentID: string, telemetry: ITelemetry, - cachedEndpoint: IIntelligenceAPIEndpointInformation | null + cachedEndpoint: IIntelligenceAPIEndpointInformation | null, + sessionID: string ): Promise { if (!cachedEndpoint) { - cachedEndpoint = await ArtemisService.getIntelligenceEndpoint(orgID, telemetry, environmentID, '') as IIntelligenceAPIEndpointInformation; // TODO - add session ID + cachedEndpoint = await ArtemisService.getIntelligenceEndpoint(orgID, telemetry, sessionID, environmentID) as IIntelligenceAPIEndpointInformation; // TODO - add session ID } return cachedEndpoint; } @@ -31,21 +32,21 @@ export async function getEndpoint( * Get component info for the active file * @returns componentInfo - Entity details for active file (form or list) */ -export async function getComponentInfo(telemetry: ITelemetry, orgUrl: string | undefined, activeFileParams: IActiveFileParams): Promise { +export async function getComponentInfo(telemetry: ITelemetry, orgUrl: string | undefined, activeFileParams: IActiveFileParams, sessionID: string): Promise { let metadataInfo = { entityName: '', formName: '' }; let componentInfo: string[] = []; if (isEntityInSupportedList(activeFileParams.dataverseEntity)) { - metadataInfo = await getEntityName(telemetry, '', activeFileParams.dataverseEntity); + metadataInfo = await getEntityName(telemetry, sessionID, activeFileParams.dataverseEntity); const dataverseToken = (await dataverseAuthentication(telemetry, orgUrl ?? '', true)).accessToken; if (activeFileParams.dataverseEntity == ADX_ENTITYFORM) { - const formColumns = await getFormXml(metadataInfo.entityName, metadataInfo.formName, orgUrl ?? '', dataverseToken, telemetry, 'sessionID'); + const formColumns = await getFormXml(metadataInfo.entityName, metadataInfo.formName, orgUrl ?? '', dataverseToken, telemetry, sessionID); componentInfo = formColumns; } else { - const entityColumns = await getEntityColumns(metadataInfo.entityName, orgUrl ?? '', dataverseToken, telemetry, 'sessionID'); + const entityColumns = await getEntityColumns(metadataInfo.entityName, orgUrl ?? '', dataverseToken, telemetry, sessionID); componentInfo = entityColumns; } }