Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: add telemetry for office agent #11831

Merged
merged 23 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fbdeeac
refactor: add telemetry for office agent
theRealHaojiangLiu Jun 14, 2024
8a9e0b9
Merge branch 'dev' of https://github.com/OfficeDev/teams-toolkit into…
theRealHaojiangLiu Jun 19, 2024
58626d5
fix: add telemetry for office agent
theRealHaojiangLiu Jun 19, 2024
b021495
fix: add telemetry for office agent for unit test
theRealHaojiangLiu Jun 19, 2024
97f3375
fix: add telemetry for office agent for unit test 2
theRealHaojiangLiu Jun 19, 2024
b45eae3
fix: add telemetry for office agent for unit test - bug fix
theRealHaojiangLiu Jun 20, 2024
7e4566a
fix: add telemetry for office agent for unit test - bug fix 2
theRealHaojiangLiu Jun 20, 2024
b7f16c9
fix: add telemetry for office agent for unit test - bug fix 3
theRealHaojiangLiu Jun 24, 2024
773470c
fix: add telemetry for office agent for unit test - remove no use import
theRealHaojiangLiu Jun 24, 2024
4d39e0c
fix: add telemetry for office agent for unit test - resolve confilt
theRealHaojiangLiu Jun 24, 2024
d1d0637
Merge remote-tracking branch 'teamsfx/dev' into user/haojiangliu/addT…
theRealHaojiangLiu Jun 26, 2024
3b6a02a
fix: add telemetry for office agent for unit test - resolve comments
theRealHaojiangLiu Jun 26, 2024
fd54ca1
fix: add telemetry for office agent for unit test - resolve comments
theRealHaojiangLiu Jun 27, 2024
f4a5120
fix: add telemetry for office agent for unit test - bug fix 4
theRealHaojiangLiu Jun 27, 2024
3805593
fix: add telemetry for office agent for unit test - bug fix 5
theRealHaojiangLiu Jun 28, 2024
1b7b992
fix: add telemetry for office agent for unit test - bug fix 6
theRealHaojiangLiu Jun 28, 2024
59afe81
fix: add telemetry for office agent for unit test - bug fix 7
theRealHaojiangLiu Jul 1, 2024
e50790b
fix: add telemetry for office agent for unit test - bug fix
theRealHaojiangLiu Jul 1, 2024
1a49d3b
fix: add telemetry for office agent for unit test - bug fix 9
theRealHaojiangLiu Jul 1, 2024
b7807f7
fix: add telemetry for office agent for unit test - bug fix 10
theRealHaojiangLiu Jul 1, 2024
f9e27a1
fix: add telemetry for office agent for unit test - bug fix 11
theRealHaojiangLiu Jul 1, 2024
20255c3
fix: add telemetry for office agent for unit test - bug fix 12
theRealHaojiangLiu Jul 1, 2024
e2ccfc1
fix: add telemetry for office agent for unit test - bug fix 13
theRealHaojiangLiu Jul 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,23 @@ import {
LanguageModelChatMessage,
LanguageModelChatMessageRole,
} from "vscode";
import { IChatTelemetryData } from "../../../chat/types";
import { ProjectMetadata } from "../../../chat/commands/create/types";
import { getCopilotResponseAsString } from "../../../chat/utils";
import { getOfficeProjectMatchSystemPrompt } from "../../officePrompts";
import { officeSampleProvider } from "./officeSamples";
import { fileTreeAdd, buildFileTree } from "../../../chat/commands/create/helper";
import { getOfficeSampleDownloadUrlInfo } from "../../utils";
import { getOfficeSample } from "../../utils";
import { getSampleFileInfo } from "@microsoft/teamsfx-core/build/component/generator/utils";
import { OfficeChatTelemetryData } from "../../telemetry";
import { OfficeXMLAddinGenerator } from "./officeXMLAddinGenerator/generator";
import { CreateProjectInputs } from "@microsoft/teamsfx-api";
import { core } from "../../../globalVariables";
import { OfficeProjectInfo } from "../../types";

export async function matchOfficeProject(
request: ChatRequest,
token: CancellationToken,
telemetryMetadata: IChatTelemetryData
telemetryData: OfficeChatTelemetryData
): Promise<ProjectMetadata | undefined> {
const allOfficeProjectMetadata = [
...getOfficeTemplateMetadata(),
Expand All @@ -39,8 +40,12 @@ export async function matchOfficeProject(
getOfficeProjectMatchSystemPrompt(allOfficeProjectMetadata),
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
];
telemetryMetadata.chatMessages.push(...messages);
const response = await getCopilotResponseAsString("copilot-gpt-4", messages, token);
let response = "";
telemetryData.chatMessages.push(...messages);
response = await getCopilotResponseAsString("copilot-gpt-4", messages, token);
telemetryData.responseChatMessages.push(
new LanguageModelChatMessage(LanguageModelChatMessageRole.Assistant, response)
);
let matchedProjectId: string;
if (response) {
try {
Expand Down Expand Up @@ -95,23 +100,27 @@ export function getOfficeTemplateMetadata(): ProjectMetadata[] {
export async function showOfficeSampleFileTree(
projectMetadata: ProjectMetadata,
response: ChatResponseStream
): Promise<string> {
): Promise<OfficeProjectInfo> {
response.markdown(
"\nWe've found a sample project that matches your description. Take a look at it below."
);
const downloadUrlInfo = await getOfficeSampleDownloadUrlInfo(projectMetadata.id);
const { samplePaths, fileUrlPrefix } = await getSampleFileInfo(downloadUrlInfo, 2);
const sample = await getOfficeSample(projectMetadata.id);
const { samplePaths, fileUrlPrefix } = await getSampleFileInfo(sample.downloadUrlInfo, 2);
const tempFolder = tmp.dirSync({ unsafeCleanup: true }).name;
const nodes = await buildFileTree(
fileUrlPrefix,
samplePaths,
tempFolder,
downloadUrlInfo.dir,
sample.downloadUrlInfo.dir,
2,
20
);
response.filetree(nodes, Uri.file(path.join(tempFolder, downloadUrlInfo.dir)));
return path.join(tempFolder, downloadUrlInfo.dir);
response.filetree(nodes, Uri.file(path.join(tempFolder, sample.downloadUrlInfo.dir)));
const result: OfficeProjectInfo = {
path: path.join(tempFolder, sample.downloadUrlInfo.dir),
host: sample.types[0],
};
return result;
}

export async function showOfficeTemplateFileTree(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,23 @@
import { OfficeChatCommand, officeChatParticipantId } from "../../consts";
import { verbatimCopilotInteraction } from "../../../chat/utils";
import { isInputHarmful } from "../../utils";
import { ICopilotChatOfficeResult } from "../../types";
import { ICopilotChatOfficeResult, OfficeProjectInfo } from "../../types";
import { describeOfficeProjectSystemPrompt } from "../../officePrompts";
import { TelemetryEvent } from "../../../telemetry/extTelemetryEvents";
import { ExtTelemetry } from "../../../telemetry/extTelemetry";
import { ChatTelemetryData } from "../../../chat/telemetry";
import { matchOfficeProject, showOfficeSampleFileTree, showOfficeTemplateFileTree } from "./helper";
import { localize } from "../../../utils/localizeUtils";
import { Planner } from "../../common/planner";
import { CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID } from "../../consts";
import { OfficeChatTelemetryBlockReasonEnum, OfficeChatTelemetryData } from "../../telemetry";

export default async function officeCreateCommandHandler(
request: ChatRequest,
context: ChatContext,
response: ChatResponseStream,
token: CancellationToken
): Promise<ICopilotChatOfficeResult> {
const officeChatTelemetryData = ChatTelemetryData.createByParticipant(
const officeChatTelemetryData = OfficeChatTelemetryData.createByParticipant(
officeChatParticipantId,
OfficeChatCommand.Create
);
Expand All @@ -39,9 +39,10 @@
);

if (request.prompt.trim() === "") {
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(localize("teamstoolkit.chatParticipants.officeAddIn.create.noPromptAnswer"));

officeChatTelemetryData.markComplete();
officeChatTelemetryData.setBlockReason(OfficeChatTelemetryBlockReasonEnum.UnsupportedInput);
officeChatTelemetryData.markComplete("fail");
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
Expand All @@ -54,67 +55,95 @@
},
};
}

const isHarmful = await isInputHarmful(request, token);
const isHarmful = await isInputHarmful(request, token, officeChatTelemetryData);
if (!isHarmful) {
const matchedResult = await matchOfficeProject(request, token, officeChatTelemetryData);
if (matchedResult) {
response.markdown(
localize("teamstoolkit.chatParticipants.officeAddIn.create.projectMatched")
);
const describeProjectChatMessages = [
describeOfficeProjectSystemPrompt(),
new LanguageModelChatMessage(
LanguageModelChatMessageRole.User,
`The project you are looking for is '${JSON.stringify(matchedResult)}'.`
),
];
officeChatTelemetryData.chatMessages.push(...describeProjectChatMessages);

await verbatimCopilotInteraction(
"copilot-gpt-3.5-turbo",
describeProjectChatMessages,
response,
token
);
if (matchedResult.type === "sample") {
const folder = await showOfficeSampleFileTree(matchedResult, response);
const sampleTitle = localize("teamstoolkit.chatParticipants.create.sample");
response.button({
command: CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID,
arguments: [folder],
title: sampleTitle,
});
try {
const matchedResult = await matchOfficeProject(request, token, officeChatTelemetryData);
if (matchedResult) {
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(
localize("teamstoolkit.chatParticipants.officeAddIn.create.projectMatched")
);
const describeProjectChatMessages = [
describeOfficeProjectSystemPrompt(),
new LanguageModelChatMessage(
LanguageModelChatMessageRole.User,
`The project you are looking for is '${JSON.stringify(matchedResult)}'.`
),
];
officeChatTelemetryData.chatMessages.push(...describeProjectChatMessages);
await verbatimCopilotInteraction(
"copilot-gpt-3.5-turbo",
describeProjectChatMessages,
response,
token
);
if (matchedResult.type === "sample") {
const sampleInfos: OfficeProjectInfo = await showOfficeSampleFileTree(
matchedResult,
response
);
const folder = sampleInfos.path;
const hostType = sampleInfos.host.toLowerCase();
const sampleTitle = localize("teamstoolkit.chatParticipants.create.sample");
officeChatTelemetryData.setHostType(hostType);
response.button({
command: CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID,
arguments: [folder, officeChatTelemetryData.requestId, matchedResult.type],
title: sampleTitle,
});
} else {
const tmpHostType = (matchedResult.data as any)?.["addin-host"].toLowerCase();
const tmpFolder = await showOfficeTemplateFileTree(matchedResult.data, response);
const templateTitle = localize("teamstoolkit.chatParticipants.create.template");
officeChatTelemetryData.setHostType(tmpHostType);
response.button({
command: CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID,
arguments: [tmpFolder, officeChatTelemetryData.requestId, matchedResult.type],
title: templateTitle,
});
}
officeChatTelemetryData.markComplete();
} else {
let chatResult: ICopilotChatOfficeResult = {};
try {
chatResult = await Planner.getInstance().processRequest(
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
request,
response,
token,
OfficeChatCommand.Create,
officeChatTelemetryData
);
officeChatTelemetryData.markComplete();
} catch (error) {
officeChatTelemetryData.markComplete("fail");

Check warning on line 120 in packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts#L120

Added line #L120 was not covered by tests
}
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
officeChatTelemetryData.measurements
);
return chatResult;
}
} catch (error) {
if ((error as Error).message.includes("off_topic")) {
officeChatTelemetryData.setBlockReason(OfficeChatTelemetryBlockReasonEnum.OffTopic);

Check warning on line 131 in packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts#L131

Added line #L131 was not covered by tests
} else {
const tmpFolder = await showOfficeTemplateFileTree(matchedResult.data, response);
const templateTitle = localize("teamstoolkit.chatParticipants.create.template");
response.button({
command: CHAT_CREATE_OFFICE_PROJECT_COMMAND_ID,
arguments: [tmpFolder],
title: templateTitle,
});
officeChatTelemetryData.setBlockReason(

Check warning on line 133 in packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts#L133

Added line #L133 was not covered by tests
OfficeChatTelemetryBlockReasonEnum.LanguageModelError
);
}
} else {
const chatResult = await Planner.getInstance().processRequest(
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
request,
response,
token,
OfficeChatCommand.Create,
officeChatTelemetryData
);
officeChatTelemetryData.markComplete();
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
officeChatTelemetryData.measurements
);
return chatResult;
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(localize("teamstoolkit.chatParticipants.officeAddIn.default.canNotAssist"));
officeChatTelemetryData.markComplete("fail");

Check warning on line 139 in packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/vscode-extension/src/officeChat/commands/create/officeCreateCommandHandler.ts#L137-L139

Added lines #L137 - L139 were not covered by tests
}
} else {
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(localize("teamstoolkit.chatParticipants.officeAddIn.harmfulInputResponse"));
officeChatTelemetryData.setBlockReason(OfficeChatTelemetryBlockReasonEnum.RAI);
officeChatTelemetryData.markComplete("fail");
}
officeChatTelemetryData.markComplete();
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@
import { localize } from "../../../utils/localizeUtils";
import { OfficeChatCommand, officeChatParticipantId } from "../../consts";
import { Planner } from "../../common/planner";
import { ChatTelemetryData } from "../../../chat/telemetry";
import { isInputHarmful } from "../../utils";
import { ICopilotChatOfficeResult } from "../../types";
import { OfficeChatTelemetryBlockReasonEnum, OfficeChatTelemetryData } from "../../telemetry";

export default async function generatecodeCommandHandler(
request: ChatRequest,
context: ChatContext,
response: ChatResponseStream,
token: CancellationToken
): Promise<ICopilotChatOfficeResult> {
const officeChatTelemetryData = ChatTelemetryData.createByParticipant(
const officeChatTelemetryData = OfficeChatTelemetryData.createByParticipant(
officeChatParticipantId,
OfficeChatCommand.GenerateCode
);
Expand All @@ -33,11 +33,12 @@
);

if (request.prompt.trim() === "") {
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(
localize("teamstoolkit.chatParticipants.officeAddIn.generateCode.noPromptAnswer")
);

officeChatTelemetryData.markComplete();
officeChatTelemetryData.setBlockReason(OfficeChatTelemetryBlockReasonEnum.UnsupportedInput);
officeChatTelemetryData.markComplete("fail");
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
Expand Down Expand Up @@ -66,26 +67,33 @@
}
}

const isHarmful = await isInputHarmful(request, token);
const isHarmful = await isInputHarmful(request, token, officeChatTelemetryData);
if (!isHarmful) {
const chatResult = await Planner.getInstance().processRequest(
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
request,
response,
token,
OfficeChatCommand.GenerateCode,
officeChatTelemetryData
);
officeChatTelemetryData.markComplete();
let chatResult: ICopilotChatOfficeResult = {};
try {
chatResult = await Planner.getInstance().processRequest(
new LanguageModelChatMessage(LanguageModelChatMessageRole.User, request.prompt),
request,
response,
token,
OfficeChatCommand.GenerateCode,
officeChatTelemetryData
);
officeChatTelemetryData.markComplete();
} catch (error) {
officeChatTelemetryData.markComplete("fail");

Check warning on line 84 in packages/vscode-extension/src/officeChat/commands/generatecode/generatecodeCommandHandler.ts

View check run for this annotation

Codecov / codecov/patch

packages/vscode-extension/src/officeChat/commands/generatecode/generatecodeCommandHandler.ts#L84

Added line #L84 was not covered by tests
}
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
officeChatTelemetryData.measurements
);
return chatResult;
} else {
officeChatTelemetryData.setTimeToFirstToken();
response.markdown(localize("teamstoolkit.chatParticipants.officeAddIn.harmfulInputResponse"));
officeChatTelemetryData.markComplete();
officeChatTelemetryData.setBlockReason(OfficeChatTelemetryBlockReasonEnum.RAI);
officeChatTelemetryData.markComplete("fail");
ExtTelemetry.sendTelemetryEvent(
TelemetryEvent.CopilotChat,
officeChatTelemetryData.properties,
Expand Down
Loading
Loading