@autobe/agent 0.7.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/AutoBeAgent.d.ts +183 -12
- package/lib/AutoBeAgent.js +249 -65
- package/lib/AutoBeAgent.js.map +1 -1
- package/lib/constants/AutoBeSystemPromptConstant.d.ts +5 -4
- package/lib/constants/AutoBeSystemPromptConstant.js.map +1 -1
- package/lib/context/AutoBeContext.d.ts +2 -2
- package/lib/factory/index.d.ts +0 -1
- package/lib/factory/index.js +0 -1
- package/lib/factory/index.js.map +1 -1
- package/lib/index.mjs +1024 -663
- package/lib/index.mjs.map +1 -1
- package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js +7 -8
- package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js.map +1 -1
- package/lib/orchestrate/analyze/orchestrateAnalyze.js +2 -5
- package/lib/orchestrate/analyze/orchestrateAnalyze.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterface.js +1 -1
- package/lib/orchestrate/interface/orchestrateInterface.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterfaceComplement.js +6 -8
- package/lib/orchestrate/interface/orchestrateInterfaceComplement.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterfaceComponents.js +9 -6
- package/lib/orchestrate/interface/orchestrateInterfaceComponents.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterfaceEndpoints.js +3 -1
- package/lib/orchestrate/interface/orchestrateInterfaceEndpoints.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterfaceOperations.js +5 -8
- package/lib/orchestrate/interface/orchestrateInterfaceOperations.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrisma.js +1 -1
- package/lib/orchestrate/prisma/orchestratePrisma.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrismaComponent.js +5 -1
- package/lib/orchestrate/prisma/orchestratePrismaComponent.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrismaCorrect.js +3 -6
- package/lib/orchestrate/prisma/orchestratePrismaCorrect.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrismaSchema.js +11 -7
- package/lib/orchestrate/prisma/orchestratePrismaSchema.js.map +1 -1
- package/lib/orchestrate/prisma/transformPrismaCorrectHistories.js +1 -1
- package/lib/orchestrate/prisma/transformPrismaCorrectHistories.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTest.js +4 -8
- package/lib/orchestrate/test/orchestrateTest.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestCorrect.d.ts +2 -2
- package/lib/orchestrate/test/orchestrateTestCorrect.js +90 -60
- package/lib/orchestrate/test/orchestrateTestCorrect.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestProgress.d.ts +3 -2
- package/lib/orchestrate/test/orchestrateTestProgress.js +75 -50
- package/lib/orchestrate/test/orchestrateTestProgress.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestScenario.d.ts +1 -1
- package/lib/orchestrate/test/orchestrateTestScenario.js +617 -208
- package/lib/orchestrate/test/orchestrateTestScenario.js.map +1 -1
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.d.ts +123 -0
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js +3 -0
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js.map +1 -0
- package/lib/orchestrate/test/transformTestCorrectHistories.d.ts +2 -1
- package/lib/orchestrate/test/transformTestCorrectHistories.js +14 -10
- package/lib/orchestrate/test/transformTestCorrectHistories.js.map +1 -1
- package/lib/orchestrate/test/transformTestProgressHistories.d.ts +7 -1
- package/lib/orchestrate/test/transformTestProgressHistories.js +20 -20
- package/lib/orchestrate/test/transformTestProgressHistories.js.map +1 -1
- package/lib/orchestrate/test/transformTestScenarioHistories.d.ts +1 -2
- package/lib/orchestrate/test/transformTestScenarioHistories.js +1 -77
- package/lib/orchestrate/test/transformTestScenarioHistories.js.map +1 -1
- package/lib/structures/IAutoBeConfig.d.ts +48 -10
- package/lib/structures/IAutoBeProps.d.ts +87 -0
- package/lib/structures/IAutoBeVendor.d.ts +64 -22
- package/lib/utils/backoffRetry.d.ts +7 -0
- package/lib/utils/backoffRetry.js +73 -0
- package/lib/utils/backoffRetry.js.map +1 -0
- package/lib/utils/enforceToolCall.d.ts +3 -0
- package/lib/utils/enforceToolCall.js +13 -0
- package/lib/utils/enforceToolCall.js.map +1 -0
- package/lib/utils/types/BackoffOptions.d.ts +12 -0
- package/lib/utils/types/BackoffOptions.js +3 -0
- package/lib/utils/types/BackoffOptions.js.map +1 -0
- package/package.json +5 -5
- package/src/AutoBeAgent.ts +252 -52
- package/src/constants/AutoBeSystemPromptConstant.ts +5 -4
- package/src/context/AutoBeContext.ts +7 -2
- package/src/factory/index.ts +0 -1
- package/src/orchestrate/analyze/AutoBeAnalyzeAgent.ts +5 -10
- package/src/orchestrate/analyze/orchestrateAnalyze.ts +2 -6
- package/src/orchestrate/interface/orchestrateInterface.ts +1 -1
- package/src/orchestrate/interface/orchestrateInterfaceComplement.ts +12 -11
- package/src/orchestrate/interface/orchestrateInterfaceComponents.ts +7 -6
- package/src/orchestrate/interface/orchestrateInterfaceEndpoints.ts +2 -1
- package/src/orchestrate/interface/orchestrateInterfaceOperations.ts +4 -9
- package/src/orchestrate/prisma/orchestratePrisma.ts +1 -0
- package/src/orchestrate/prisma/orchestratePrismaComponent.ts +4 -1
- package/src/orchestrate/prisma/orchestratePrismaCorrect.ts +6 -7
- package/src/orchestrate/prisma/orchestratePrismaSchema.ts +10 -7
- package/src/orchestrate/test/orchestrateTest.ts +6 -13
- package/src/orchestrate/test/orchestrateTestCorrect.ts +127 -78
- package/src/orchestrate/test/orchestrateTestProgress.ts +88 -47
- package/src/orchestrate/test/orchestrateTestScenario.ts +194 -105
- package/src/orchestrate/test/structures/IAutoBeTestScenarioApplication.ts +132 -0
- package/src/orchestrate/test/transformTestCorrectHistories.ts +14 -10
- package/src/orchestrate/test/transformTestProgressHistories.ts +25 -22
- package/src/orchestrate/test/transformTestScenarioHistories.ts +0 -79
- package/src/structures/IAutoBeConfig.ts +48 -10
- package/src/structures/IAutoBeProps.ts +91 -0
- package/src/structures/IAutoBeVendor.ts +64 -22
- package/src/utils/backoffRetry.ts +84 -0
- package/src/utils/enforceToolCall.ts +13 -0
- package/src/utils/types/BackoffOptions.ts +15 -0
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
import { IAgenticaController, MicroAgentica } from "@agentica/core";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
AutoBeOpenApi,
|
|
4
|
+
AutoBeTestScenarioEvent,
|
|
5
|
+
AutoBeTestWriteEvent,
|
|
6
|
+
} from "@autobe/interface";
|
|
7
|
+
import {
|
|
8
|
+
ILlmApplication,
|
|
9
|
+
ILlmSchema,
|
|
10
|
+
OpenApiTypeChecker,
|
|
11
|
+
} from "@samchon/openapi";
|
|
4
12
|
import { IPointer } from "tstl";
|
|
5
13
|
import typia from "typia";
|
|
6
14
|
|
|
7
15
|
import { AutoBeContext } from "../../context/AutoBeContext";
|
|
8
16
|
import { assertSchemaModel } from "../../context/assertSchemaModel";
|
|
17
|
+
import { enforceToolCall } from "../../utils/enforceToolCall";
|
|
9
18
|
import { transformTestProgressHistories } from "./transformTestProgressHistories";
|
|
10
19
|
|
|
11
20
|
export async function orchestrateTestProgress<Model extends ILlmSchema.Model>(
|
|
12
21
|
ctx: AutoBeContext<Model>,
|
|
13
|
-
scenarios:
|
|
14
|
-
): Promise<
|
|
22
|
+
scenarios: AutoBeTestScenarioEvent.IScenario[],
|
|
23
|
+
): Promise<AutoBeTestWriteEvent[]> {
|
|
15
24
|
const start: Date = new Date();
|
|
16
25
|
let complete: number = 0;
|
|
17
26
|
|
|
18
|
-
const events:
|
|
27
|
+
const events: AutoBeTestWriteEvent[] = await Promise.all(
|
|
19
28
|
/**
|
|
20
|
-
* Generate test code for each scenario. Maps through
|
|
21
|
-
*
|
|
22
|
-
*
|
|
29
|
+
* Generate test code for each scenario. Maps through plans array to create
|
|
30
|
+
* individual test code implementations. Each scenario is processed to
|
|
31
|
+
* generate corresponding test code and progress events.
|
|
23
32
|
*/
|
|
24
33
|
scenarios.map(async (scenario) => {
|
|
25
34
|
const code: ICreateTestCodeProps = await process(ctx, scenario);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
type: "testProgress",
|
|
35
|
+
const event: AutoBeTestWriteEvent = {
|
|
36
|
+
type: "testWrite",
|
|
29
37
|
created_at: start.toISOString(),
|
|
30
38
|
filename: `${code.domain}/${scenario.functionName}.ts`,
|
|
31
39
|
content: code.content,
|
|
@@ -53,27 +61,20 @@ export async function orchestrateTestProgress<Model extends ILlmSchema.Model>(
|
|
|
53
61
|
*/
|
|
54
62
|
async function process<Model extends ILlmSchema.Model>(
|
|
55
63
|
ctx: AutoBeContext<Model>,
|
|
56
|
-
scenario:
|
|
64
|
+
scenario: AutoBeTestScenarioEvent.IScenario,
|
|
57
65
|
): Promise<ICreateTestCodeProps> {
|
|
58
66
|
const pointer: IPointer<ICreateTestCodeProps | null> = {
|
|
59
67
|
value: null,
|
|
60
68
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const dtoFiles = Object.entries(ctx.state().interface?.files ?? {})
|
|
71
|
-
.filter(([filename]) => {
|
|
72
|
-
return filename.startsWith("src/api/structures/");
|
|
73
|
-
})
|
|
74
|
-
.reduce<Record<string, string>>((acc, [filename, content]) => {
|
|
75
|
-
return Object.assign(acc, { [filename]: content });
|
|
76
|
-
}, {});
|
|
69
|
+
const document: AutoBeOpenApi.IDocument = filterDocument(
|
|
70
|
+
scenario,
|
|
71
|
+
ctx.state().interface!.document,
|
|
72
|
+
);
|
|
73
|
+
const files: [string, string][] = Object.entries(
|
|
74
|
+
await ctx.compiler.interface.compile(document),
|
|
75
|
+
);
|
|
76
|
+
const filter = (prefix: string) =>
|
|
77
|
+
Object.fromEntries(files.filter(([key]) => key.startsWith(prefix)));
|
|
77
78
|
|
|
78
79
|
const agentica = new MicroAgentica({
|
|
79
80
|
model: ctx.model,
|
|
@@ -81,7 +82,12 @@ async function process<Model extends ILlmSchema.Model>(
|
|
|
81
82
|
config: {
|
|
82
83
|
...(ctx.config ?? {}),
|
|
83
84
|
},
|
|
84
|
-
histories: transformTestProgressHistories(
|
|
85
|
+
histories: transformTestProgressHistories({
|
|
86
|
+
scenario: scenario,
|
|
87
|
+
dto: filter("src/api/structures"),
|
|
88
|
+
sdk: filter("src/api/functional"),
|
|
89
|
+
e2e: filter("test/features"),
|
|
90
|
+
}),
|
|
85
91
|
controllers: [
|
|
86
92
|
createApplication({
|
|
87
93
|
model: ctx.model,
|
|
@@ -90,26 +96,61 @@ async function process<Model extends ILlmSchema.Model>(
|
|
|
90
96
|
},
|
|
91
97
|
}),
|
|
92
98
|
],
|
|
99
|
+
tokenUsage: ctx.usage(),
|
|
93
100
|
});
|
|
101
|
+
enforceToolCall(agentica);
|
|
94
102
|
|
|
95
|
-
agentica.
|
|
96
|
-
if (event.body.tools) event.body.tool_choice = "required";
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
await agentica.conversate(
|
|
100
|
-
[
|
|
101
|
-
"Create test code for below scenario:",
|
|
102
|
-
"",
|
|
103
|
-
"```json",
|
|
104
|
-
JSON.stringify(scenario, null, 2),
|
|
105
|
-
"```",
|
|
106
|
-
].join("\n"),
|
|
107
|
-
);
|
|
108
|
-
|
|
103
|
+
await agentica.conversate("Create e2e test functions.");
|
|
109
104
|
if (pointer.value === null) throw new Error("Failed to create test code.");
|
|
110
105
|
return pointer.value;
|
|
111
106
|
}
|
|
112
107
|
|
|
108
|
+
export function filterDocument(
|
|
109
|
+
scenario: AutoBeTestScenarioEvent.IScenario,
|
|
110
|
+
document: AutoBeOpenApi.IDocument,
|
|
111
|
+
): AutoBeOpenApi.IDocument {
|
|
112
|
+
const operations: AutoBeOpenApi.IOperation[] = document.operations.filter(
|
|
113
|
+
(op) => {
|
|
114
|
+
if (
|
|
115
|
+
scenario.endpoint.method === op.method &&
|
|
116
|
+
scenario.endpoint.path === op.path
|
|
117
|
+
) {
|
|
118
|
+
return true;
|
|
119
|
+
} else if (
|
|
120
|
+
scenario.dependencies.some(
|
|
121
|
+
(dp) =>
|
|
122
|
+
dp.endpoint.method === op.method && dp.endpoint.path === op.path,
|
|
123
|
+
)
|
|
124
|
+
) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
const components: AutoBeOpenApi.IComponents = {
|
|
130
|
+
schemas: {},
|
|
131
|
+
};
|
|
132
|
+
const visit = (typeName: string) => {
|
|
133
|
+
OpenApiTypeChecker.visit({
|
|
134
|
+
components: document.components,
|
|
135
|
+
schema: { $ref: `#/components/schemas/${typeName}` },
|
|
136
|
+
closure: (s) => {
|
|
137
|
+
if (OpenApiTypeChecker.isReference(s)) {
|
|
138
|
+
const key: string = s.$ref.split("/").pop()!;
|
|
139
|
+
components.schemas[key] = document.components.schemas[key];
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
for (const op of operations) {
|
|
145
|
+
if (op.requestBody) visit(op.requestBody.typeName);
|
|
146
|
+
if (op.responseBody) visit(op.responseBody.typeName);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
operations,
|
|
150
|
+
components,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
113
154
|
function createApplication<Model extends ILlmSchema.Model>(props: {
|
|
114
155
|
model: Model;
|
|
115
156
|
build: (next: ICreateTestCodeProps) => void;
|
|
@@ -181,7 +222,7 @@ interface ICreateTestCodeProps {
|
|
|
181
222
|
* #### Execution Strategy
|
|
182
223
|
*
|
|
183
224
|
* - Outline step-by-step test execution flow
|
|
184
|
-
* - Plan error handling and exception
|
|
225
|
+
* - Plan error handling and exception plans
|
|
185
226
|
* - Define cleanup and teardown procedures
|
|
186
227
|
* - Identify dependencies and prerequisites
|
|
187
228
|
*
|
|
@@ -191,12 +232,12 @@ interface ICreateTestCodeProps {
|
|
|
191
232
|
* 1. Prepare valid article data with required fields
|
|
192
233
|
* 2. Execute POST request to create article
|
|
193
234
|
* 3. Validate response structure and data integrity
|
|
194
|
-
* 4. Test error
|
|
235
|
+
* 4. Test error plans (missing fields, invalid data)
|
|
195
236
|
* 5. Verify database state changes
|
|
196
|
-
* 6. Reconsider the
|
|
237
|
+
* 6. Reconsider the scenario if it doesn't follow the Test Generation
|
|
197
238
|
* Guildelines.
|
|
198
239
|
*/
|
|
199
|
-
|
|
240
|
+
scenario: string;
|
|
200
241
|
|
|
201
242
|
/**
|
|
202
243
|
* Functional domain classification for test organization.
|
|
@@ -1,150 +1,253 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
IAgenticaController,
|
|
3
|
+
IAgenticaHistoryJson,
|
|
4
|
+
MicroAgentica,
|
|
5
|
+
} from "@agentica/core";
|
|
6
|
+
import { AutoBeOpenApi } from "@autobe/interface";
|
|
7
|
+
import { AutoBeTestScenarioEvent } from "@autobe/interface";
|
|
8
|
+
import { ILlmApplication, ILlmSchema, IValidation } from "@samchon/openapi";
|
|
5
9
|
import { IPointer } from "tstl";
|
|
6
10
|
import typia from "typia";
|
|
11
|
+
import { v4 } from "uuid";
|
|
7
12
|
|
|
13
|
+
import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant";
|
|
8
14
|
import { AutoBeContext } from "../../context/AutoBeContext";
|
|
9
15
|
import { assertSchemaModel } from "../../context/assertSchemaModel";
|
|
10
|
-
import {
|
|
16
|
+
import { divideArray } from "../../utils/divideArray";
|
|
17
|
+
import { enforceToolCall } from "../../utils/enforceToolCall";
|
|
18
|
+
import { IAutoBeTestScenarioApplication } from "./structures/IAutoBeTestScenarioApplication";
|
|
11
19
|
|
|
12
20
|
export async function orchestrateTestScenario<Model extends ILlmSchema.Model>(
|
|
13
21
|
ctx: AutoBeContext<Model>,
|
|
14
22
|
): Promise<AutoBeTestScenarioEvent> {
|
|
15
|
-
const files = Object.entries(ctx.state().interface?.files ?? {})
|
|
16
|
-
.filter(([filename]) => {
|
|
17
|
-
return filename.startsWith("test/features/api/");
|
|
18
|
-
})
|
|
19
|
-
.reduce<Record<string, string>>((acc, [filename, content]) => {
|
|
20
|
-
return Object.assign(acc, { [filename]: content });
|
|
21
|
-
}, {});
|
|
22
|
-
|
|
23
23
|
const operations = ctx.state().interface?.document.operations ?? [];
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
summary: it.summary,
|
|
30
|
-
description: it.description,
|
|
31
|
-
parameters: it.parameters,
|
|
32
|
-
requestBody: it.requestBody,
|
|
33
|
-
responseBody: it.responseBody,
|
|
34
|
-
};
|
|
35
|
-
});
|
|
24
|
+
if (operations.length === 0) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"Cannot write test scenarios because these are no operations.",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
36
29
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
30
|
+
const exclude: IAutoBeTestScenarioApplication.IScenarioGroup[] = [];
|
|
31
|
+
let include: AutoBeOpenApi.IOperation[] = Array.from(operations);
|
|
32
|
+
|
|
33
|
+
do {
|
|
34
|
+
const matrix = divideArray({ array: include, capacity: 30 });
|
|
35
|
+
|
|
36
|
+
await Promise.all(
|
|
37
|
+
matrix.map(async (_include) => {
|
|
38
|
+
exclude.push(
|
|
39
|
+
...(await execute(
|
|
40
|
+
ctx,
|
|
41
|
+
operations,
|
|
42
|
+
_include,
|
|
43
|
+
exclude.map((x) => x.endpoint),
|
|
44
|
+
)),
|
|
45
|
+
);
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
include = include.filter((op) => {
|
|
50
|
+
if (
|
|
51
|
+
exclude.some(
|
|
52
|
+
(pg) =>
|
|
53
|
+
pg.endpoint.method === op.method && pg.endpoint.path === op.path,
|
|
54
|
+
)
|
|
55
|
+
) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
} while (include.length > 0);
|
|
61
61
|
|
|
62
62
|
return {
|
|
63
63
|
type: "testScenario",
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
step: ctx.state().analyze?.step ?? 0,
|
|
65
|
+
scenarios: exclude.flatMap((pg) => {
|
|
66
|
+
return pg.scenarios.map((plan) => {
|
|
67
|
+
return {
|
|
68
|
+
endpoint: pg.endpoint,
|
|
69
|
+
draft: plan.draft,
|
|
70
|
+
functionName: plan.functionName,
|
|
71
|
+
dependencies: plan.dependsOn,
|
|
72
|
+
} satisfies AutoBeTestScenarioEvent.IScenario;
|
|
73
|
+
});
|
|
74
|
+
}),
|
|
75
|
+
created_at: new Date().toISOString(),
|
|
76
|
+
} as AutoBeTestScenarioEvent;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
|
-
async
|
|
79
|
+
const execute = async <Model extends ILlmSchema.Model>(
|
|
73
80
|
ctx: AutoBeContext<Model>,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
const pointer: IPointer<
|
|
79
|
-
value:
|
|
81
|
+
ops: AutoBeOpenApi.IOperation[],
|
|
82
|
+
include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
83
|
+
exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
84
|
+
) => {
|
|
85
|
+
const pointer: IPointer<IAutoBeTestScenarioApplication.IScenarioGroup[]> = {
|
|
86
|
+
value: [],
|
|
80
87
|
};
|
|
81
|
-
|
|
82
|
-
const agentica = new MicroAgentica({
|
|
88
|
+
const agentica: MicroAgentica<Model> = new MicroAgentica({
|
|
83
89
|
model: ctx.model,
|
|
84
90
|
vendor: ctx.vendor,
|
|
85
91
|
config: {
|
|
86
|
-
...(ctx.config ?? {
|
|
87
|
-
|
|
88
|
-
describe:
|
|
89
|
-
return "Answer only 'completion' or 'failure'.";
|
|
90
|
-
},
|
|
92
|
+
...(ctx.config ?? {}),
|
|
93
|
+
executor: {
|
|
94
|
+
describe: null,
|
|
91
95
|
},
|
|
92
96
|
},
|
|
93
97
|
tokenUsage: ctx.usage(),
|
|
94
|
-
histories:
|
|
95
|
-
...transformTestScenarioHistories(ctx.state(), endpoints, files),
|
|
96
|
-
],
|
|
98
|
+
histories: createHistoryProperties(ops, include, exclude),
|
|
97
99
|
controllers: [
|
|
98
100
|
createApplication({
|
|
99
101
|
model: ctx.model,
|
|
100
102
|
build: (next) => {
|
|
101
|
-
pointer.value
|
|
103
|
+
pointer.value ??= [];
|
|
104
|
+
pointer.value.push(...next.scenarioGroups);
|
|
102
105
|
},
|
|
103
106
|
}),
|
|
104
107
|
],
|
|
105
108
|
});
|
|
109
|
+
enforceToolCall(agentica);
|
|
106
110
|
|
|
107
|
-
agentica.
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
await agentica.conversate(`create test scenarios.`);
|
|
112
|
+
if (pointer.value.length === 0) {
|
|
113
|
+
throw new Error("Failed to create test plans.");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return pointer.value;
|
|
117
|
+
};
|
|
110
118
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
const createHistoryProperties = (
|
|
120
|
+
operations: AutoBeOpenApi.IOperation[],
|
|
121
|
+
include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
122
|
+
exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
123
|
+
) => [
|
|
124
|
+
{
|
|
125
|
+
id: v4(),
|
|
126
|
+
created_at: new Date().toISOString(),
|
|
127
|
+
type: "systemMessage",
|
|
128
|
+
text: AutoBeSystemPromptConstant.TEST_SCENARIO,
|
|
129
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
130
|
+
{
|
|
131
|
+
id: v4(),
|
|
132
|
+
created_at: new Date().toISOString(),
|
|
133
|
+
type: "systemMessage",
|
|
134
|
+
text: [
|
|
135
|
+
"Below are the full operations. Please refer to this.",
|
|
136
|
+
"Your role is to draft all test cases for each given Operation.",
|
|
137
|
+
"It is also permissible to write multiple test codes on a single endpoint.",
|
|
138
|
+
"However, rather than meaningless tests, business logic tests should be written and an E2E test situation should be assumed.",
|
|
114
139
|
"",
|
|
115
140
|
"```json",
|
|
116
|
-
JSON.stringify(
|
|
141
|
+
JSON.stringify(
|
|
142
|
+
operations.map((el) => ({
|
|
143
|
+
path: el.path,
|
|
144
|
+
method: el.method,
|
|
145
|
+
summary: el.summary,
|
|
146
|
+
})),
|
|
147
|
+
),
|
|
117
148
|
"```",
|
|
118
149
|
].join("\n"),
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
150
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
151
|
+
{
|
|
152
|
+
id: v4(),
|
|
153
|
+
created_at: new Date().toISOString(),
|
|
154
|
+
type: "systemMessage",
|
|
155
|
+
text: [
|
|
156
|
+
"# Included in Test Plan",
|
|
157
|
+
include
|
|
158
|
+
.map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
|
|
159
|
+
.join("\n"),
|
|
160
|
+
"",
|
|
161
|
+
"# Excluded from Test Plan",
|
|
162
|
+
"These are the endpoints that have already been used in test codes generated as part of a plan group.",
|
|
163
|
+
"These endpoints do not need to be tested again.",
|
|
164
|
+
"However, it is allowed to reference or depend on these endpoints when writing test codes for other purposes.",
|
|
165
|
+
exclude
|
|
166
|
+
.map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
|
|
167
|
+
.join("\n"),
|
|
168
|
+
].join("\n"),
|
|
169
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
170
|
+
];
|
|
124
171
|
|
|
125
172
|
function createApplication<Model extends ILlmSchema.Model>(props: {
|
|
126
173
|
model: Model;
|
|
127
|
-
build: (next:
|
|
174
|
+
build: (next: IAutoBeTestScenarioApplication.IProps) => void;
|
|
128
175
|
}): IAgenticaController.IClass<Model> {
|
|
129
176
|
assertSchemaModel(props.model);
|
|
130
177
|
|
|
131
178
|
const application: ILlmApplication<Model> = collection[
|
|
132
179
|
props.model
|
|
133
180
|
] as unknown as ILlmApplication<Model>;
|
|
181
|
+
|
|
182
|
+
application.functions[0].validate = (next: unknown): IValidation => {
|
|
183
|
+
const result: IValidation<IAutoBeTestScenarioApplication.IProps> =
|
|
184
|
+
typia.validate<IAutoBeTestScenarioApplication.IProps>(next);
|
|
185
|
+
if (result.success === false) return result;
|
|
186
|
+
|
|
187
|
+
const errors: IValidation.IError[] = [];
|
|
188
|
+
result.data.scenarioGroups.forEach((pg, i, arr) => {
|
|
189
|
+
arr.forEach((target, j) => {
|
|
190
|
+
if (
|
|
191
|
+
i !== j &&
|
|
192
|
+
target.endpoint.method === pg.endpoint.method &&
|
|
193
|
+
target.endpoint.path === pg.endpoint.path
|
|
194
|
+
) {
|
|
195
|
+
if (
|
|
196
|
+
!errors.some(
|
|
197
|
+
(el) =>
|
|
198
|
+
el.path !== `planGroups[${j}].path` &&
|
|
199
|
+
el.value !== target.endpoint.path,
|
|
200
|
+
)
|
|
201
|
+
) {
|
|
202
|
+
errors.push({
|
|
203
|
+
path: `planGroups[${j}].path`,
|
|
204
|
+
expected: `planGroup's {method + path} cannot duplicated.`,
|
|
205
|
+
value: target.endpoint.path,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (
|
|
210
|
+
!errors.some(
|
|
211
|
+
(el) =>
|
|
212
|
+
el.path !== `planGroups[${j}].method` &&
|
|
213
|
+
el.value !== target.endpoint.method,
|
|
214
|
+
)
|
|
215
|
+
) {
|
|
216
|
+
errors.push({
|
|
217
|
+
path: `planGroups[${j}].method`,
|
|
218
|
+
expected: `planGroup's {method + path} cannot duplicated.`,
|
|
219
|
+
value: target.endpoint.method,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (errors.length !== 0) {
|
|
227
|
+
console.log(JSON.stringify(errors, null, 2), "errors");
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
errors,
|
|
231
|
+
data: next,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
};
|
|
134
237
|
return {
|
|
135
238
|
protocol: "class",
|
|
136
|
-
name: "Make
|
|
239
|
+
name: "Make test plans",
|
|
137
240
|
application,
|
|
138
241
|
execute: {
|
|
139
242
|
makeScenario: (next) => {
|
|
140
243
|
props.build(next);
|
|
141
244
|
},
|
|
142
|
-
} satisfies
|
|
245
|
+
} satisfies IAutoBeTestScenarioApplication,
|
|
143
246
|
};
|
|
144
247
|
}
|
|
145
248
|
|
|
146
249
|
const claude = typia.llm.application<
|
|
147
|
-
|
|
250
|
+
IAutoBeTestScenarioApplication,
|
|
148
251
|
"claude",
|
|
149
252
|
{
|
|
150
253
|
reference: true;
|
|
@@ -152,7 +255,7 @@ const claude = typia.llm.application<
|
|
|
152
255
|
>();
|
|
153
256
|
const collection = {
|
|
154
257
|
chatgpt: typia.llm.application<
|
|
155
|
-
|
|
258
|
+
IAutoBeTestScenarioApplication,
|
|
156
259
|
"chatgpt",
|
|
157
260
|
{ reference: true }
|
|
158
261
|
>(),
|
|
@@ -160,19 +263,5 @@ const collection = {
|
|
|
160
263
|
llama: claude,
|
|
161
264
|
deepseek: claude,
|
|
162
265
|
"3.1": claude,
|
|
163
|
-
"3.0": typia.llm.application<
|
|
266
|
+
"3.0": typia.llm.application<IAutoBeTestScenarioApplication, "3.0">(),
|
|
164
267
|
};
|
|
165
|
-
|
|
166
|
-
interface IApplication {
|
|
167
|
-
/**
|
|
168
|
-
* Make user scenarios for the given endpoints.
|
|
169
|
-
*
|
|
170
|
-
* @param props Properties containing the endpoints and user scenarios.
|
|
171
|
-
*/
|
|
172
|
-
makeScenario(props: IMakeScenarioProps): void;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
interface IMakeScenarioProps {
|
|
176
|
-
/** Array of user scenarios. */
|
|
177
|
-
scenarios: AutoBeTest.IScenario[];
|
|
178
|
-
}
|