Skip to content

Commit

Permalink
perf(ai-generator): add prompt suggestions (#12838)
Browse files Browse the repository at this point in the history
Co-authored-by: rentu <rentu>
  • Loading branch information
SLdragon authored Dec 3, 2024
1 parent d009588 commit 519d6f0
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 1 deletion.
31 changes: 31 additions & 0 deletions packages/fx-core/src/component/generator/apiSpec/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1519,9 +1519,40 @@ export async function updateForCustomApi(
// 4. update code
await updateCodeForCustomApi(specItems, language, destinationPath, openapiSpecFileName, needAuth);

// 5. add prompt suggestions
const manifestPath = path.join(destinationPath, AppPackageFolderName, ManifestTemplateFileName);
await updatePromptSuggestions(specItems, manifestPath);

return warnings;
}

async function updatePromptSuggestions(specItems: SpecObject[], manifestPath: string) {
const descriptions: string[] = specItems
.map((item) => item.item.summary ?? item.item.description)
.filter((item): item is string => item !== undefined)
.slice(0, 10);

const manifestRes = await manifestUtils._readAppManifest(manifestPath);
if (manifestRes.isOk()) {
const manifest = manifestRes.value;
manifest.bots![0].commandLists = [
{
scopes: ["personal"],
commands: descriptions.map((des) => {
return {
title: des.slice(0, 32),
description: des.slice(0, 128),
};
}),
},
];

await manifestUtils._writeAppManifest(manifest, manifestPath);
} else {
throw manifestRes.error;
}
}

const EnvNamePostfix = "REGISTRATION_ID";

export function getEnvName(authName: string): string {
Expand Down
101 changes: 100 additions & 1 deletion packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,31 @@ describe("updateForCustomApi", async () => {
},
} as OpenAPIV3.Document;

const manifest: TeamsAppManifest = {
manifestVersion: "version",
id: "mock-app-id",
name: { short: "short-name" },
description: { short: "", full: "" },
version: "version",
icons: { outline: "outline.png", color: "color.png" },
accentColor: "#ffffff",
developer: {
privacyUrl: "",
websiteUrl: "",
termsOfUseUrl: "",
name: "developer-name",
},
bots: [
{
botId: "${{BOT_ID}}",
scopes: ["personal", "team", "groupChat"],
supportsFiles: false,
isNotificationOnly: false,
},
],
validDomains: ["valid-domain"],
};

afterEach(async () => {
sandbox.restore();
});
Expand All @@ -861,9 +886,52 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));

sandbox
.stub(manifestUtils, "_writeAppManifest")
.callsFake(async (updatedManifest, manifestPath) => {
expect(manifestPath.replace(/\\/g, "/")).to.be.equal("path/appPackage/manifest.json");
expect(updatedManifest.bots![0].commandLists![0].commands[0].title).to.be.equal(
"Returns a greeting"
);
expect(updatedManifest.bots![0].commandLists![0].commands[1].title).to.be.equal(
"Create a pet"
);
return ok(undefined);
});
await CopilotPluginHelper.updateForCustomApi(spec, "typescript", "path", "openapi.yaml");
});

it("read manifest failed", async () => {
sandbox.stub(fs, "ensureDir").resolves();
sandbox.stub(fs, "writeFile").callsFake((file, data) => {
if (file === path.join("path", "src", "prompts", "chat", "skprompt.txt")) {
expect(data).to.contains("The following is a conversation with an AI assistant.");
} else if (file === path.join("path", "src", "adaptiveCard", "hello.json")) {
expect(data).to.contains("getHello");
} else if (file === path.join("path", "src", "prompts", "chat", "actions.json")) {
expect(data).to.contains("getHello");
} else if (file === path.join("path", "src", "app", "app.ts")) {
expect(data).to.contains(`app.ai.action("getHello"`);
expect(data).not.to.contains("{{");
expect(data).not.to.contains("// Replace with action code");
}
});
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox
.stub(manifestUtils, "_readAppManifest")
.resolves(err(new SystemError("test", "", "", "")));
try {
await CopilotPluginHelper.updateForCustomApi(spec, "typescript", "path", "openapi.yaml");
assert.fail("should throw error");
} catch (e) {
expect(e.source).to.be.equal("test");
}
});

it("happy path: should contain warning if generate adaptive card failed", async () => {
sandbox.stub(fs, "ensureDir").resolves();
sandbox.stub(fs, "writeFile").callsFake((file, data) => {
Expand All @@ -886,6 +954,9 @@ describe("updateForCustomApi", async () => {
.stub(AdaptiveCardGenerator, "generateAdaptiveCard")
.throws(new Error("generate adaptive card failed"));

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));

const result = await CopilotPluginHelper.updateForCustomApi(
spec,
"typescript",
Expand Down Expand Up @@ -924,6 +995,8 @@ describe("updateForCustomApi", async () => {
expect(data).not.to.contains("// Replace with action code");
}
});
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
Expand Down Expand Up @@ -968,6 +1041,9 @@ describe("updateForCustomApi", async () => {
[{ type: WarningType.GenerateJsonDataFailed, content: "generate json data failed" }],
]);

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));

const result = await CopilotPluginHelper.updateForCustomApi(
spec,
"typescript",
Expand Down Expand Up @@ -1009,6 +1085,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(spec, "javascript", "path", "openapi.yaml");
});

Expand All @@ -1030,6 +1108,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code # Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(spec, "python", "path", "openapi.yaml");
});

Expand Down Expand Up @@ -1060,7 +1140,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
//sandbox fs.readdir(destinationPath)
sandbox.stub(fs, "readdir").resolves(["MyApp.csproj"] as any);
await CopilotPluginHelper.updateForCustomApi(spec, "csharp", "path", "openapi.yaml");
Expand All @@ -1086,6 +1167,8 @@ describe("updateForCustomApi", async () => {
}
});

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
Expand Down Expand Up @@ -1114,6 +1197,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(limitedSpec, "javascript", "path", "openapi.yaml");
});

Expand All @@ -1140,6 +1225,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(limitedSpec, "javascript", "path", "openapi.yaml");
});

Expand Down Expand Up @@ -1190,6 +1277,8 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(limitedSpec, "javascript", "path", "openapi.yaml");
expect(mockWriteFile.calledThrice).to.be.true;
});
Expand Down Expand Up @@ -1282,6 +1371,9 @@ describe("updateForCustomApi", async () => {
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
await CopilotPluginHelper.updateForCustomApi(newSpec, "typescript", "path", "openapi.yaml");
});

Expand Down Expand Up @@ -1405,6 +1497,9 @@ describe("updateForCustomApi", async () => {
expect(data).not.to.contains("// Replace with action code");
}
});

sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
Expand Down Expand Up @@ -1496,6 +1591,8 @@ describe("updateForCustomApi", async () => {
expect(data).not.to.contains("// Replace with action code");
}
});
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
Expand Down Expand Up @@ -1566,6 +1663,8 @@ describe("updateForCustomApi", async () => {
expect(data).not.to.contains("// Replace with action code");
}
});
sandbox.stub(manifestUtils, "_readAppManifest").resolves(ok(manifest));
sandbox.stub(manifestUtils, "_writeAppManifest").resolves(ok(undefined));
sandbox
.stub(fs, "readFile")
.resolves(Buffer.from("test code // Replace with action code {{OPENAPI_SPEC_PATH}}"));
Expand Down

0 comments on commit 519d6f0

Please sign in to comment.