Skip to content

Commit

Permalink
perf(ai-generator): update action generate logic (#12457)
Browse files Browse the repository at this point in the history
* perf(ai-generator): update action generate logic

* perf: update test case

* perf: update test case

* perf: update test case

---------

Co-authored-by: rentu <rentu>
  • Loading branch information
SLdragon authored Sep 26, 2024
1 parent f88679d commit de0fdaa
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 1 deletion.
52 changes: 51 additions & 1 deletion packages/fx-core/src/component/generator/apiSpec/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,41 @@ async function updateAdaptiveCardForCustomApi(
}
}

function filterSchema(schema: OpenAPIV3.SchemaObject): OpenAPIV3.SchemaObject {
const filteredSchema: any = { type: schema.type };

if (schema.description) {
filteredSchema.description = schema.description;
}

if (schema.type === "object" && schema.properties) {
filteredSchema.properties = {};
filteredSchema.required = schema.required;
for (const key in schema.properties) {
const property = schema.properties[key] as OpenAPIV3.SchemaObject;
if (property.type === "object") {
filteredSchema.properties[key] = filterSchema(property as OpenAPIV3.SchemaObject);
filteredSchema.required = schema.required;
} else if (property.type === "array") {
filteredSchema.properties[key] = {
type: "array",
items: filterSchema(property.items as OpenAPIV3.SchemaObject),
description: property.description,
};
} else {
filteredSchema.properties[key] = {
type: property.type,
description: property.description,
};
}
}
} else if (schema.type === "array" && schema.items) {
filteredSchema.items = filterSchema(schema.items as OpenAPIV3.SchemaObject);
}

return filteredSchema;
}

async function updateActionForCustomApi(
specItems: SpecObject[],
language: string,
Expand Down Expand Up @@ -1096,7 +1131,7 @@ async function updateActionForCustomApi(
required: [],
};
}
parameters.properties[paramType].properties[param.name] = schema;
parameters.properties[paramType].properties[param.name] = filterSchema(schema);
parameters.properties[paramType].properties[param.name].description =
param.description ?? "";
if (param.required) {
Expand All @@ -1108,6 +1143,21 @@ async function updateActionForCustomApi(
}
}

const requestBody = item.item.requestBody as OpenAPIV3.RequestBodyObject;
if (requestBody) {
const content = requestBody.content;
if (content) {
const contentSchema = content["application/json"].schema as OpenAPIV3.SchemaObject;
if (Object.keys(contentSchema).length !== 0) {
parameters.properties["body"] = filterSchema(contentSchema);
parameters.properties["body"].description = requestBody.description ?? "";
if (requestBody.required) {
parameters.required.push("body");
}
}
}
}

actions.push({
name: item.item.operationId,
description: item.item.description ?? item.item.summary,
Expand Down
126 changes: 126 additions & 0 deletions packages/fx-core/tests/component/generator/apiSpecGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,132 @@ describe("updateForCustomApi", async () => {
await CopilotPluginHelper.updateForCustomApi(newSpec, "typescript", "path", "openapi.yaml");
});

it("happy path with spec request body and schema contains format", async () => {
const newSpec = {
openapi: "3.0.0",
info: {
title: "My API",
version: "1.0.0",
},
description: "test",
paths: {
"/hello": {
get: {
operationId: "getHello",
summary: "Returns a greeting",
parameters: [
{
name: "query",
in: "query",
schema: { type: "string" },
required: true,
},
{
name: "query2",
in: "query",
schema: { type: "string" },
requried: false,
},
{
name: "query3",
in: "query",
schema: { type: "string" },
requried: true,
description: "test",
},
{
name: "query4",
in: "query",
schema: {
type: "array",
items: {
type: "string",
format: "test",
},
},
},
],
responses: {
"200": {
description: "",
content: {
"application/json": {
schema: {
type: "string",
},
},
},
},
},
},
post: {
operationId: "createPet",
summary: "Create a pet",
description: "",
requestBody: {
required: true,
description: "request body description",
content: {
"application/json": {
schema: {
type: "object",
required: ["date"],
properties: {
date: {
type: "string",
description: "",
format: "date-time",
},
array: {
type: "array",
items: {
type: "string",
format: "test",
},
},
object: {
type: "object",
properties: {
nestedObjProperty: {
type: "string",
description: "",
format: "test",
},
},
},
},
},
},
},
},
},
},
},
} as OpenAPIV3.Document;
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");
expect(data).to.contains("body");
expect(data).to.not.contains("format");
expect(data).to.contains("nestedObjProperty");
expect(data).to.contains("array");
} 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}}"));
await CopilotPluginHelper.updateForCustomApi(newSpec, "typescript", "path", "openapi.yaml");
});

it("happy path with spec with auth", async () => {
const authSpec = {
openapi: "3.0.0",
Expand Down

0 comments on commit de0fdaa

Please sign in to comment.