diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json
index f41bfd9e..afa8ac2c 100644
--- a/l10n/bundle.l10n.json
+++ b/l10n/bundle.l10n.json
@@ -254,4 +254,4 @@
"The {0} represents profile's Azure Cloud Instances"
]
}
-}
\ No newline at end of file
+}
diff --git a/loc/translations-export/vscode-powerplatform.xlf b/loc/translations-export/vscode-powerplatform.xlf
index 69c3dcd4..3145b496 100644
--- a/loc/translations-export/vscode-powerplatform.xlf
+++ b/loc/translations-export/vscode-powerplatform.xlf
@@ -318,6 +318,10 @@ The {3} represents Dataverse Environment's Organization ID (GUID)
+
+
+
{0} represents the environment name
diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts
index 55da4726..4f4eead9 100644
--- a/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts
+++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipant.ts
@@ -6,6 +6,7 @@
import * as vscode from 'vscode';
import { createChatParticipant } from '../ChatParticipantUtils';
import { IComponentInfo, IPowerPagesChatResult } from './PowerPagesChatParticipantTypes';
+import { ITelemetry } from "../../OneDSLoggerTelemetry/telemetry/ITelemetry";
import TelemetryReporter from '@vscode/extension-telemetry';
import { sendApiRequest } from '../../copilot/IntelligenceApiService';
import { PacWrapper } from '../../../client/pac/PacWrapper';
@@ -13,11 +14,10 @@ import { intelligenceAPIAuthentication } from '../../services/AuthenticationProv
import { ActiveOrgOutput } from '../../../client/pac/PacTypes';
import { AUTHENTICATION_FAILED_MSG, COPILOT_NOT_AVAILABLE_MSG, DISCLAIMER_MESSAGE, NO_PROMPT_MESSAGE, PAC_AUTH_NOT_FOUND, POWERPAGES_CHAT_PARTICIPANT_ID, RESPONSE_AWAITED_MSG, SKIP_CODES, STATER_PROMPTS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_INVOKED, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_ORG_DETAILS_NOT_FOUND, VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO, WELCOME_MESSAGE, WELCOME_PROMPT } from './PowerPagesChatParticipantConstants';
import { ORG_DETAILS_KEY, handleOrgChangeSuccess, initializeOrgDetails } from '../../utilities/OrgHandlerUtils';
-import { getComponentInfo, getEndpoint, provideChatParticipantFollowups } from './PowerPagesChatParticipantUtils';
+import { createAndReferenceLocation, getComponentInfo, getEndpoint, provideChatParticipantFollowups } from './PowerPagesChatParticipantUtils';
import { checkCopilotAvailability, getActiveEditorContent } from '../../utilities/Utils';
import { IIntelligenceAPIEndpointInformation } from '../../services/Interfaces';
import { v4 as uuidv4 } from 'uuid';
-import { ITelemetry } from '../../OneDSLoggerTelemetry/telemetry/ITelemetry';
import { orgChangeErrorEvent, orgChangeEvent } from '../../../client/OrgChangeNotifier';
export class PowerPagesChatParticipant {
@@ -131,7 +131,7 @@ export class PowerPagesChatParticipant {
if (userPrompt === WELCOME_PROMPT) {
stream.markdown(WELCOME_MESSAGE);
- return{
+ return {
metadata: {
command: STATER_PROMPTS
}
@@ -139,9 +139,7 @@ export class PowerPagesChatParticipant {
}
if (!userPrompt) {
-
stream.markdown(NO_PROMPT_MESSAGE);
-
return {
metadata: {
command: STATER_PROMPTS
@@ -149,23 +147,31 @@ export class PowerPagesChatParticipant {
};
}
+ const { activeFileContent, activeFileUri, startLine, endLine, activeFileParams } = getActiveEditorContent();
+
+ const location = activeFileUri ? createAndReferenceLocation(activeFileUri, startLine, endLine) : undefined;
+
+ if (location) {
+ stream.reference(location);
+ }
+
if (request.command) {
//TODO: Handle command scenarios
} else {
- const { activeFileParams } = getActiveEditorContent();
-
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 llmResponse = await sendApiRequest([{ displayText: userPrompt, code: activeFileContent }], 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;
this.telemetry.sendTelemetryEvent(VSCODE_EXTENSION_GITHUB_POWER_PAGES_AGENT_SCENARIO, { scenario: scenario, sessionId: this.powerPagesAgentSessionId, orgId: this.orgID, environmentId: this.environmentID })
llmResponse.forEach((response: { displayText: string | vscode.MarkdownString; code: string; }) => {
+
if (response.displayText) {
stream.markdown(response.displayText);
+ stream.markdown('\n');
}
if (response.code && !SKIP_CODES.includes(response.code)) {
stream.markdown('\n```javascript\n' + response.code + '\n```');
diff --git a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts
index 94ff0628..570f73b3 100644
--- a/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts
+++ b/src/common/chat-participants/powerpages/PowerPagesChatParticipantUtils.ts
@@ -57,6 +57,15 @@ export function isEntityInSupportedList(entity: string): boolean {
return SUPPORTED_ENTITIES.includes(entity);
}
+export function createAndReferenceLocation(activeFileUri: vscode.Uri, startLine: number, endLine: number): vscode.Location {
+
+ const positionStart = new vscode.Position(startLine, 0),
+ positionEnd = new vscode.Position(endLine, 0),
+ activeFileRange = new vscode.Range(positionStart, positionEnd),
+ location = new vscode.Location(activeFileUri, activeFileRange);
+
+ return location;
+}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function provideChatParticipantFollowups(result: IPowerPagesChatResult, _context: vscode.ChatContext, _token: vscode.CancellationToken) {
if (result.metadata.command === STATER_PROMPTS) {
@@ -68,3 +77,4 @@ export function provideChatParticipantFollowups(result: IPowerPagesChatResult, _
];
}
}
+
diff --git a/src/common/copilot/IntelligenceApiService.ts b/src/common/copilot/IntelligenceApiService.ts
index 555bea75..fa0a4214 100644
--- a/src/common/copilot/IntelligenceApiService.ts
+++ b/src/common/copilot/IntelligenceApiService.ts
@@ -56,7 +56,6 @@ export async function sendApiRequest(userPrompt: UserPrompt[], activeFileParams:
}
}
-
const requestInit: RequestInit = {
method: "POST",
headers: {
diff --git a/src/common/copilot/PowerPagesCopilot.ts b/src/common/copilot/PowerPagesCopilot.ts
index e225848c..3b15a33b 100644
--- a/src/common/copilot/PowerPagesCopilot.ts
+++ b/src/common/copilot/PowerPagesCopilot.ts
@@ -11,7 +11,7 @@ import { v4 as uuidv4 } from 'uuid'
import { PacWrapper } from "../../client/pac/PacWrapper";
import { ITelemetry } from "../OneDSLoggerTelemetry/telemetry/ITelemetry";
import { ADX_ENTITYFORM, ADX_ENTITYLIST, AUTH_CREATE_FAILED, AUTH_CREATE_MESSAGE, AuthProfileNotFound, COPILOT_IN_POWERPAGES, COPILOT_UNAVAILABLE, CopilotStylePathSegments, EXPLAIN_CODE, SELECTED_CODE_INFO, SELECTED_CODE_INFO_ENABLED, THUMBS_DOWN, THUMBS_UP, UserPrompt, WebViewMessage, sendIconSvg } from "./constants";
-import { IActiveFileParams, IOrgInfo } from './model';
+import { IOrgInfo } from './model';
import { checkCopilotAvailability, escapeDollarSign, getActiveEditorContent, getNonce, getSelectedCode, getSelectedCodeLineRange, getUserName, openWalkthrough, showConnectedOrgMessage, showInputBoxAndGetOrgUrl, showProgressWithNotification } from "../utilities/Utils";
import { CESUserFeedback } from "./user-feedback/CESSurvey";
import { ActiveOrgOutput } from "../../client/pac/PacTypes";
@@ -236,8 +236,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
sendTelemetryEvent(this.telemetry, { eventName: CopilotUserPromptedEvent, copilotSessionId: sessionID, aibEndpoint: this.aibEndpoint ?? '', orgId: orgID, isSuggestedPrompt: String(data.value.isSuggestedPrompt), crossGeoDataMovementEnabledPPACFlag: this.crossGeoDataMovementEnabledPPACFlag }); //TODO: Add active Editor info
orgID
? (async () => {
- const { activeFileParams } = getActiveEditorContent();
- await this.authenticateAndSendAPIRequest(data.value.userPrompt, activeFileParams, orgID, this.telemetry);
+ await this.authenticateAndSendAPIRequest(data.value.userPrompt, orgID, this.telemetry);
})()
: (() => {
this.sendMessageToWebview({ type: 'apiResponse', value: AuthProfileNotFound });
@@ -359,7 +358,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
}
}
- private async authenticateAndSendAPIRequest(data: UserPrompt[], activeFileParams: IActiveFileParams, orgID: string, telemetry: ITelemetry) {
+ private async authenticateAndSendAPIRequest(data: UserPrompt[], orgID: string, telemetry: ITelemetry) {
return intelligenceAPIAuthentication(telemetry, sessionID, orgID)
.then(async ({ accessToken, user, userId }) => {
intelligenceApiToken = accessToken;
@@ -368,6 +367,8 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
this.sendMessageToWebview({ type: 'userName', value: userName });
+ const { activeFileContent, activeFileParams } = getActiveEditorContent();
+
let metadataInfo = { entityName: '', formName: '' };
let componentInfo: string[] = [];
@@ -385,7 +386,7 @@ export class PowerPagesCopilot implements vscode.WebviewViewProvider {
}
}
- return sendApiRequest(data, activeFileParams, orgID, intelligenceApiToken, sessionID, metadataInfo.entityName, componentInfo, telemetry, this.aibEndpoint, this.geoName, this.crossGeoDataMovementEnabledPPACFlag);
+ return sendApiRequest([{ displayText: data[0].displayText, code: activeFileContent }], activeFileParams, orgID, intelligenceApiToken, sessionID, metadataInfo.entityName, componentInfo, telemetry, this.aibEndpoint, this.geoName, this.crossGeoDataMovementEnabledPPACFlag);
})
.then(apiResponse => {
this.sendMessageToWebview({ type: 'apiResponse', value: apiResponse });
diff --git a/src/common/copilot/model.ts b/src/common/copilot/model.ts
index 5cd25e6e..df8e6be0 100644
--- a/src/common/copilot/model.ts
+++ b/src/common/copilot/model.ts
@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
+import * as vscode from 'vscode';
+
export interface IFeedbackData {
TenantId: string;
Geo: string;
@@ -19,7 +21,10 @@ export interface IActiveFileParams {
export interface IActiveFileData {
activeFileParams: IActiveFileParams;
- activeFileContent: string
+ activeFileContent: string;
+ activeFileUri: vscode.Uri | undefined;
+ startLine: number;
+ endLine: number;
}
export interface IOrgInfo {
diff --git a/src/common/utilities/Utils.ts b/src/common/utilities/Utils.ts
index c502ee27..402d3004 100644
--- a/src/common/utilities/Utils.ts
+++ b/src/common/utilities/Utils.ts
@@ -7,7 +7,7 @@ import * as vscode from "vscode";
import { EXTENSION_ID, EXTENSION_NAME, SETTINGS_EXPERIMENTAL_STORE_NAME } from "../constants";
import { CUSTOM_TELEMETRY_FOR_POWER_PAGES_SETTING_NAME } from "../OneDSLoggerTelemetry/telemetryConstants";
import { COPILOT_UNAVAILABLE, DataverseEntityNameMap, EntityFieldMap, FieldTypeMap } from "../copilot/constants";
-import { IActiveFileData, IActiveFileParams } from "../copilot/model";
+import { IActiveFileData } from "../copilot/model";
import { ITelemetry } from "../OneDSLoggerTelemetry/telemetry/ITelemetry";
import { sendTelemetryEvent } from "../copilot/telemetry/copilotTelemetry";
import { getDisabledOrgList, getDisabledTenantList } from "../copilot/utils/copilotUtil";
@@ -141,28 +141,50 @@ export function getUserAgent(): string {
export function getActiveEditorContent(): IActiveFileData {
const activeEditor = vscode.window.activeTextEditor;
- const activeFileData: IActiveFileData = {
- activeFileContent: '',
- activeFileParams: {
- dataverseEntity: '',
- entityField: '',
- fieldType: ''
- } as IActiveFileParams
- };
- if (activeEditor) {
- const document = activeEditor.document;
- const fileName = document.fileName;
- const relativeFileName = vscode.workspace.asRelativePath(fileName);
-
- const activeFileParams: string[] = getLastThreePartsOfFileName(relativeFileName);
- activeFileData.activeFileContent = document.getText();
- activeFileData.activeFileParams.dataverseEntity = DataverseEntityNameMap.get(activeFileParams[0]) || "";
- activeFileData.activeFileParams.entityField = EntityFieldMap.get(activeFileParams[1]) || "";
- activeFileData.activeFileParams.fieldType = FieldTypeMap.get(activeFileParams[2]) || "";
+ if (!activeEditor) {
+ return { activeFileContent: '', startLine: 0, endLine: 0, activeFileUri: undefined, activeFileParams: { dataverseEntity: '', entityField: '', fieldType: '' } };
}
- return activeFileData;
+ const document = activeEditor.document;
+ const fileName = document.fileName;
+ const relativeFileName = vscode.workspace.asRelativePath(fileName);
+ const activeFileUri = document.uri;
+ const activeFileParams: string[] = getLastThreePartsOfFileName(relativeFileName);
+
+ let activeFileContent = document.getText();
+ let startLine = 0;
+ let endLine = document.lineCount;
+
+ const selectedCode = getSelectedCode(activeEditor);
+ const selectedCodeLineRange = getSelectedCodeLineRange(activeEditor);
+
+ if (selectedCode.length > 0) {
+ activeFileContent = selectedCode;
+ startLine = selectedCodeLineRange.start;
+ endLine = selectedCodeLineRange.end;
+ }
+ /**
+ * Uncomment the below code to pass the visible code to the copilot based on the token limit.
+ */
+ //else if (document.getText().length > 100) { // Define the token limit for context passing
+ // const { code, startLine: visibleStart, endLine: visibleEnd } = getVisibleCode(activeEditor);
+ // activeFileContent = code;
+ // startLine = visibleStart;
+ // endLine = visibleEnd;
+ // }
+
+ return {
+ activeFileContent,
+ startLine,
+ endLine,
+ activeFileUri,
+ activeFileParams: {
+ dataverseEntity: DataverseEntityNameMap.get(activeFileParams[0]) || "",
+ entityField: EntityFieldMap.get(activeFileParams[1]) || "",
+ fieldType: FieldTypeMap.get(activeFileParams[2]) || ""
+ }
+ };
}
export function checkCopilotAvailability(
@@ -186,3 +208,14 @@ export function checkCopilotAvailability(
return true;
}
}
+
+export function getVisibleCode(editor: vscode.TextEditor): { code: string; startLine: number; endLine: number; } {
+ const visibleRanges = editor.visibleRanges;
+ const visibleCode = visibleRanges.map(range => editor.document.getText(range)).join('\n');
+ const firstVisibleRange = visibleRanges[0];
+ return {
+ code: visibleCode,
+ startLine: firstVisibleRange.start.line,
+ endLine: firstVisibleRange.end.line
+ };
+}