Skip to content
This repository was archived by the owner on Mar 23, 2025. It is now read-only.

Commit 04a30fb

Browse files
committed
add fiter option
1 parent 002e5d1 commit 04a30fb

File tree

2 files changed

+165
-98
lines changed

2 files changed

+165
-98
lines changed

packages/core/src/__tests__/index.test.ts

+87-53
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { mkdir, rm, rmdir, writeFile } from "fs/promises";
2-
import generateDandoriTasks, { DandoriTask } from "../index";
2+
import generateDandoriTasks, {
3+
ChatGPTFunctionCallModel,
4+
DandoriTaskOptionalProperty,
5+
DandoriTaskProperty,
6+
DandoriTaskRequiredProperty,
7+
} from "../index";
38
import {
49
describe,
510
beforeEach,
@@ -184,12 +189,50 @@ describe("generateDandoriTasks", () => {
184189
},
185190
},
186191
} as const;
187-
const requiredProperties: readonly (keyof DandoriTask)[] = [
192+
const requiredProperties: readonly DandoriTaskRequiredProperty[] = [
188193
"id",
189194
"name",
190195
"fromTaskIdList",
191196
];
192197
const logPrefix = "Generating tasks";
198+
const createOpenAiChatGptArguments = ({
199+
source,
200+
model = "gpt-3.5-turbo-0613",
201+
filter = Object.keys(functionCallTaskProperties) as DandoriTaskProperty[],
202+
}: {
203+
source: string;
204+
model?: ChatGPTFunctionCallModel;
205+
filter?: DandoriTaskProperty[];
206+
}) => ({
207+
messages: [{ role: "user", content: source }],
208+
model,
209+
function_call: { name: functionCallName },
210+
functions: [
211+
{
212+
name: functionCallName,
213+
description:
214+
"Get the tasks flow which will be used like Gantt chart.",
215+
parameters: {
216+
type: "object",
217+
properties: {
218+
tasks: {
219+
type: "array",
220+
items: {
221+
type: "object",
222+
required: requiredProperties,
223+
properties: Object.fromEntries(
224+
filter.map((prop) => [
225+
prop,
226+
functionCallTaskProperties[prop],
227+
]),
228+
),
229+
},
230+
},
231+
},
232+
},
233+
},
234+
],
235+
});
193236

194237
beforeEach(() => {
195238
process.env[openApiKeyPropName] = apiKey;
@@ -199,7 +242,7 @@ describe("generateDandoriTasks", () => {
199242
expect(process.env[openApiKeyPropName]).toBe(apiKey);
200243
});
201244

202-
describe("with model argument", () => {
245+
describe("with options which include model argument", () => {
203246
let result: Awaited<ReturnType<typeof generateDandoriTasks>>;
204247
const source = "with model argument";
205248
const model = "gpt-4-0613";
@@ -211,33 +254,46 @@ describe("generateDandoriTasks", () => {
211254
});
212255

213256
it("called chat.completions.create with valid arguments", () => {
214-
expect(openAI.chat.completions.create).toBeCalledWith({
215-
messages: [{ role: "user", content: source }],
216-
model,
217-
function_call: { name: functionCallName },
218-
functions: [
219-
{
220-
name: functionCallName,
221-
description:
222-
"Get the tasks flow which will be used like Gantt chart.",
223-
parameters: {
224-
type: "object",
225-
properties: {
226-
tasks: {
227-
type: "array",
228-
items: {
229-
type: "object",
230-
required: requiredProperties,
231-
properties: functionCallTaskProperties,
232-
},
233-
},
234-
},
235-
},
236-
},
237-
],
257+
expect(openAI.chat.completions.create).toBeCalledWith(
258+
createOpenAiChatGptArguments({ source, model }),
259+
);
260+
});
261+
262+
it("called logger.debug with valid arguments", () => {
263+
expect(logger.debug).toBeCalledWith(openAiResArguments.tasks);
264+
});
265+
266+
it("return tasks", () => {
267+
expect(result).toStrictEqual(openAiResArguments.tasks);
268+
});
269+
270+
it("called log with valid statement", () => {
271+
expect(runPromisesSequentiallyMock.mock.calls[0][1]).toContain(
272+
logPrefix,
273+
);
274+
});
275+
});
276+
277+
describe("with options which include filter argument", () => {
278+
let result: Awaited<ReturnType<typeof generateDandoriTasks>>;
279+
const source = "with filter argument";
280+
const filter: DandoriTaskOptionalProperty[] = ["deadline"];
281+
282+
beforeEach(async () => {
283+
result = await generateDandoriTasks(source, {
284+
filter,
238285
});
239286
});
240287

288+
it("called chat.completions.create with valid arguments", () => {
289+
expect(openAI.chat.completions.create).toBeCalledWith(
290+
createOpenAiChatGptArguments({
291+
source,
292+
filter: [...filter, ...requiredProperties],
293+
}),
294+
);
295+
});
296+
241297
it("called logger.debug with valid arguments", () => {
242298
expect(logger.debug).toBeCalledWith(openAiResArguments.tasks);
243299
});
@@ -253,7 +309,7 @@ describe("generateDandoriTasks", () => {
253309
});
254310
});
255311

256-
describe("without model argument", () => {
312+
describe("without options", () => {
257313
let result: Awaited<ReturnType<typeof generateDandoriTasks>>;
258314
const source = "without model argument";
259315

@@ -262,31 +318,9 @@ describe("generateDandoriTasks", () => {
262318
});
263319

264320
it("called chat.completions.create with valid arguments", () => {
265-
expect(openAI.chat.completions.create).toBeCalledWith({
266-
messages: [{ role: "user", content: source }],
267-
model: "gpt-3.5-turbo-0613",
268-
function_call: { name: functionCallName },
269-
functions: [
270-
{
271-
name: functionCallName,
272-
description:
273-
"Get the tasks flow which will be used like Gantt chart.",
274-
parameters: {
275-
type: "object",
276-
properties: {
277-
tasks: {
278-
type: "array",
279-
items: {
280-
type: "object",
281-
required: requiredProperties,
282-
properties: functionCallTaskProperties,
283-
},
284-
},
285-
},
286-
},
287-
},
288-
],
289-
});
321+
expect(openAI.chat.completions.create).toBeCalledWith(
322+
createOpenAiChatGptArguments({ source }),
323+
);
290324
});
291325

292326
it("called logger.debug with valid arguments", () => {

packages/core/src/index.ts

+78-45
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ export type ChatGPTFunctionCallModel = "gpt-3.5-turbo-0613" | "gpt-4-0613";
1212
const defaultChatGPTFunctionCallModel: ChatGPTFunctionCallModel =
1313
"gpt-3.5-turbo-0613";
1414

15-
export type GenerateDandoriTasksOptions = {
16-
chatGPTModel?: ChatGPTFunctionCallModel;
17-
envFilePath?: string;
18-
};
19-
2015
export type DandoriTask = {
2116
id: string;
2217
name: string;
@@ -29,6 +24,24 @@ export type DandoriTask = {
2924
fromTaskIdList: string[];
3025
};
3126

27+
export type DandoriTaskProperty = keyof DandoriTask;
28+
29+
export type DandoriTaskRequiredProperty = Extract<
30+
DandoriTaskProperty,
31+
"id" | "name" | "fromTaskIdList"
32+
>;
33+
34+
export type DandoriTaskOptionalProperty = Exclude<
35+
DandoriTaskProperty,
36+
DandoriTaskRequiredProperty
37+
>;
38+
39+
export type GenerateDandoriTasksOptions = {
40+
chatGPTModel?: ChatGPTFunctionCallModel;
41+
envFilePath?: string;
42+
filter?: DandoriTaskOptionalProperty[];
43+
};
44+
3245
type FunctionCallValue = {
3346
type: "string" | "array" | "object";
3447
description?: string;
@@ -40,52 +53,62 @@ const excludePropertyPrompt =
4053
"If not provided, this property shouldn't be included.";
4154
const generateIdPrompt = "If not provided, return generated unique ID.";
4255

43-
const functionCallTaskProperties: Record<keyof DandoriTask, FunctionCallValue> =
44-
{
45-
id: {
56+
const requiredFunctionCallTaskProperties: Record<
57+
DandoriTaskRequiredProperty,
58+
FunctionCallValue
59+
> = {
60+
id: {
61+
type: "string",
62+
description: `The task ID. ${generateIdPrompt}`,
63+
},
64+
name: {
65+
type: "string",
66+
description: "The task name",
67+
},
68+
fromTaskIdList: {
69+
type: "array",
70+
description: "Task IDs to be executed before this task",
71+
items: {
4672
type: "string",
47-
description: `The task ID. ${generateIdPrompt}`,
4873
},
49-
name: {
50-
type: "string",
51-
description: "The task name",
52-
},
53-
description: {
54-
type: "string",
55-
description: "The task description",
56-
},
57-
deadline: {
58-
type: "string",
59-
description: `The task deadline which is used by JavaScript Date constructor arguments. ${excludePropertyPrompt}`,
60-
},
61-
assignee: {
62-
type: "object",
63-
description: `The task assignee. ${excludePropertyPrompt}`,
64-
properties: {
65-
id: {
66-
type: "string",
67-
description: `The task assignee ID. ${generateIdPrompt}`,
68-
},
69-
name: {
70-
type: "string",
71-
description: "The task assignee name.",
72-
},
74+
},
75+
} as const;
76+
77+
const optionalFunctionCallTaskProperties: Record<
78+
DandoriTaskOptionalProperty,
79+
FunctionCallValue
80+
> = {
81+
description: {
82+
type: "string",
83+
description: "The task description",
84+
},
85+
deadline: {
86+
type: "string",
87+
description: `The task deadline which is used by JavaScript Date constructor arguments. ${excludePropertyPrompt}`,
88+
},
89+
assignee: {
90+
type: "object",
91+
description: `The task assignee. ${excludePropertyPrompt}`,
92+
properties: {
93+
id: {
94+
type: "string",
95+
description: `The task assignee ID. ${generateIdPrompt}`,
7396
},
74-
},
75-
fromTaskIdList: {
76-
type: "array",
77-
description: "Task IDs to be executed before this task",
78-
items: {
97+
name: {
7998
type: "string",
99+
description: "The task assignee name.",
80100
},
81101
},
82-
} as const;
102+
},
103+
};
104+
105+
const requiredProperties: readonly DandoriTaskRequiredProperty[] = Object.keys(
106+
requiredFunctionCallTaskProperties,
107+
) as DandoriTaskRequiredProperty[];
83108

84-
const requiredProperties: readonly (keyof DandoriTask)[] = [
85-
"id",
86-
"name",
87-
"fromTaskIdList",
88-
];
109+
const optionalProperties: readonly DandoriTaskOptionalProperty[] = Object.keys(
110+
optionalFunctionCallTaskProperties,
111+
) as DandoriTaskOptionalProperty[];
89112

90113
const functionCallName = "get_tasks_flow";
91114

@@ -105,6 +128,13 @@ export default async function generateDandoriTasks(
105128
const openai = new OpenAI();
106129
const model: ChatGPTFunctionCallModel =
107130
options?.chatGPTModel ?? defaultChatGPTFunctionCallModel;
131+
const filterProperties = options?.filter ?? optionalProperties;
132+
const filteredOptionalFunctionCallTaskProperties = Object.fromEntries(
133+
filterProperties.map((filterProperty) => [
134+
filterProperty,
135+
optionalFunctionCallTaskProperties[filterProperty],
136+
]),
137+
);
108138
const [completion] = await runPromisesSequentially(
109139
[
110140
() =>
@@ -125,7 +155,10 @@ export default async function generateDandoriTasks(
125155
items: {
126156
type: "object",
127157
required: requiredProperties,
128-
properties: functionCallTaskProperties,
158+
properties: {
159+
...requiredFunctionCallTaskProperties,
160+
...filteredOptionalFunctionCallTaskProperties,
161+
},
129162
},
130163
},
131164
},

0 commit comments

Comments
 (0)