@autobe/agent 0.8.0 → 0.9.1

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.
Files changed (91) hide show
  1. package/lib/AutoBeAgent.d.ts +183 -12
  2. package/lib/AutoBeAgent.js +247 -65
  3. package/lib/AutoBeAgent.js.map +1 -1
  4. package/lib/constants/AutoBeSystemPromptConstant.d.ts +4 -3
  5. package/lib/constants/AutoBeSystemPromptConstant.js.map +1 -1
  6. package/lib/context/AutoBeContext.d.ts +2 -2
  7. package/lib/factory/index.d.ts +0 -1
  8. package/lib/factory/index.js +0 -1
  9. package/lib/factory/index.js.map +1 -1
  10. package/lib/index.mjs +1195 -834
  11. package/lib/index.mjs.map +1 -1
  12. package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js +1 -1
  13. package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js.map +1 -1
  14. package/lib/orchestrate/interface/orchestrateInterface.js +1 -1
  15. package/lib/orchestrate/interface/orchestrateInterface.js.map +1 -1
  16. package/lib/orchestrate/prisma/orchestratePrisma.js +1 -1
  17. package/lib/orchestrate/prisma/orchestratePrisma.js.map +1 -1
  18. package/lib/orchestrate/prisma/orchestratePrismaCorrect.js +1 -1
  19. package/lib/orchestrate/prisma/orchestratePrismaCorrect.js.map +1 -1
  20. package/lib/orchestrate/test/compileTestScenario.d.ts +5 -0
  21. package/lib/orchestrate/test/compileTestScenario.js +56 -0
  22. package/lib/orchestrate/test/compileTestScenario.js.map +1 -0
  23. package/lib/orchestrate/test/filterTestFileName.d.ts +1 -0
  24. package/lib/orchestrate/test/filterTestFileName.js +13 -0
  25. package/lib/orchestrate/test/filterTestFileName.js.map +1 -0
  26. package/lib/orchestrate/test/orchestrateTest.js +10 -11
  27. package/lib/orchestrate/test/orchestrateTest.js.map +1 -1
  28. package/lib/orchestrate/test/orchestrateTestCorrect.d.ts +2 -2
  29. package/lib/orchestrate/test/orchestrateTestCorrect.js +91 -73
  30. package/lib/orchestrate/test/orchestrateTestCorrect.js.map +1 -1
  31. package/lib/orchestrate/test/orchestrateTestScenario.d.ts +2 -2
  32. package/lib/orchestrate/test/orchestrateTestScenario.js +616 -237
  33. package/lib/orchestrate/test/orchestrateTestScenario.js.map +1 -1
  34. package/lib/orchestrate/test/orchestrateTestWrite.d.ts +4 -0
  35. package/lib/orchestrate/test/{orchestrateTestProgress.js → orchestrateTestWrite.js} +37 -51
  36. package/lib/orchestrate/test/orchestrateTestWrite.js.map +1 -0
  37. package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.d.ts +123 -0
  38. package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js +3 -0
  39. package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js.map +1 -0
  40. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.d.ts +5 -0
  41. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.js +3 -0
  42. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.js.map +1 -0
  43. package/lib/orchestrate/test/transformTestCorrectHistories.d.ts +2 -1
  44. package/lib/orchestrate/test/transformTestCorrectHistories.js +4 -4
  45. package/lib/orchestrate/test/transformTestCorrectHistories.js.map +1 -1
  46. package/lib/orchestrate/test/transformTestScenarioHistories.d.ts +1 -2
  47. package/lib/orchestrate/test/transformTestScenarioHistories.js +1 -77
  48. package/lib/orchestrate/test/transformTestScenarioHistories.js.map +1 -1
  49. package/lib/orchestrate/test/transformTestWriteHistories.d.ts +7 -0
  50. package/lib/orchestrate/test/transformTestWriteHistories.js +47 -0
  51. package/lib/orchestrate/test/transformTestWriteHistories.js.map +1 -0
  52. package/lib/structures/IAutoBeConfig.d.ts +48 -10
  53. package/lib/structures/IAutoBeProps.d.ts +87 -0
  54. package/lib/structures/IAutoBeVendor.d.ts +64 -22
  55. package/lib/utils/backoffRetry.d.ts +7 -0
  56. package/lib/utils/backoffRetry.js +73 -0
  57. package/lib/utils/backoffRetry.js.map +1 -0
  58. package/lib/utils/types/BackoffOptions.d.ts +12 -0
  59. package/lib/utils/types/BackoffOptions.js +3 -0
  60. package/lib/utils/types/BackoffOptions.js.map +1 -0
  61. package/package.json +4 -4
  62. package/src/AutoBeAgent.ts +251 -51
  63. package/src/constants/AutoBeSystemPromptConstant.ts +4 -3
  64. package/src/context/AutoBeContext.ts +7 -2
  65. package/src/factory/index.ts +0 -1
  66. package/src/orchestrate/analyze/AutoBeAnalyzeAgent.ts +1 -1
  67. package/src/orchestrate/interface/orchestrateInterface.ts +1 -1
  68. package/src/orchestrate/prisma/orchestratePrisma.ts +1 -0
  69. package/src/orchestrate/prisma/orchestratePrismaCorrect.ts +4 -2
  70. package/src/orchestrate/test/compileTestScenario.ts +63 -0
  71. package/src/orchestrate/test/filterTestFileName.ts +9 -0
  72. package/src/orchestrate/test/orchestrateTest.ts +11 -17
  73. package/src/orchestrate/test/orchestrateTestCorrect.ts +152 -100
  74. package/src/orchestrate/test/orchestrateTestScenario.ts +195 -151
  75. package/src/orchestrate/test/{orchestrateTestProgress.ts → orchestrateTestWrite.ts} +29 -44
  76. package/src/orchestrate/test/structures/IAutoBeTestScenarioApplication.ts +132 -0
  77. package/src/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.ts +5 -0
  78. package/src/orchestrate/test/transformTestCorrectHistories.ts +4 -4
  79. package/src/orchestrate/test/transformTestScenarioHistories.ts +0 -79
  80. package/src/orchestrate/test/transformTestWriteHistories.ts +53 -0
  81. package/src/structures/IAutoBeConfig.ts +48 -10
  82. package/src/structures/IAutoBeProps.ts +91 -0
  83. package/src/structures/IAutoBeVendor.ts +64 -22
  84. package/src/utils/backoffRetry.ts +84 -0
  85. package/src/utils/types/BackoffOptions.ts +15 -0
  86. package/lib/orchestrate/test/orchestrateTestProgress.d.ts +0 -4
  87. package/lib/orchestrate/test/orchestrateTestProgress.js.map +0 -1
  88. package/lib/orchestrate/test/transformTestProgressHistories.d.ts +0 -2
  89. package/lib/orchestrate/test/transformTestProgressHistories.js +0 -47
  90. package/lib/orchestrate/test/transformTestProgressHistories.js.map +0 -1
  91. package/src/orchestrate/test/transformTestProgressHistories.ts +0 -51
@@ -1,198 +1,256 @@
1
- import { IAgenticaController, MicroAgentica } from "@agentica/core";
2
- import { AutoBeOpenApi, AutoBeTest } from "@autobe/interface";
3
- import { AutoBeTestScenarioEvent } from "@autobe/interface/src/events/AutoBeTestScenarioEvent";
4
- import { ILlmApplication, ILlmSchema } from "@samchon/openapi";
5
- import { HashMap, HashSet, IPointer } from "tstl";
1
+ import {
2
+ IAgenticaController,
3
+ IAgenticaHistoryJson,
4
+ MicroAgentica,
5
+ } from "@agentica/core";
6
+ import {
7
+ AutoBeOpenApi,
8
+ AutoBeTestScenario,
9
+ AutoBeTestScenarioEvent,
10
+ } from "@autobe/interface";
11
+ import { ILlmApplication, ILlmSchema, IValidation } from "@samchon/openapi";
12
+ import { IPointer } from "tstl";
6
13
  import typia from "typia";
14
+ import { v4 } from "uuid";
7
15
 
16
+ import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant";
8
17
  import { AutoBeContext } from "../../context/AutoBeContext";
9
18
  import { assertSchemaModel } from "../../context/assertSchemaModel";
10
19
  import { divideArray } from "../../utils/divideArray";
11
20
  import { enforceToolCall } from "../../utils/enforceToolCall";
12
- import { OpenApiEndpointComparator } from "../interface/OpenApiEndpointComparator";
13
- import { transformTestScenarioHistories } from "./transformTestScenarioHistories";
21
+ import { IAutoBeTestScenarioApplication } from "./structures/IAutoBeTestScenarioApplication";
14
22
 
15
23
  export async function orchestrateTestScenario<Model extends ILlmSchema.Model>(
16
24
  ctx: AutoBeContext<Model>,
17
- capacity: number = 4,
18
25
  ): Promise<AutoBeTestScenarioEvent> {
19
- const files = Object.entries(ctx.state().interface?.files ?? {})
20
- .filter(([filename]) => {
21
- return filename.startsWith("test/features/api/");
22
- })
23
- .reduce<Record<string, string>>((acc, [filename, content]) => {
24
- return Object.assign(acc, { [filename]: content });
25
- }, {});
26
-
27
26
  const operations = ctx.state().interface?.document.operations ?? [];
28
- const endpoints: Omit<AutoBeOpenApi.IOperation, "specification">[] =
29
- operations.map((it) => {
30
- return {
31
- method: it.method,
32
- path: it.path,
33
- summary: it.summary,
34
- description: it.description,
35
- parameters: it.parameters,
36
- requestBody: it.requestBody,
37
- responseBody: it.responseBody,
38
- };
39
- });
27
+ if (operations.length === 0) {
28
+ throw new Error(
29
+ "Cannot write test scenarios because these are no operations.",
30
+ );
31
+ }
40
32
 
41
- const matrix: AutoBeOpenApi.IEndpoint[][] = divideArray({
42
- array: endpoints,
43
- capacity,
44
- });
45
- const start: Date = new Date();
46
-
47
- let completed: number = 0;
48
-
49
- const scenarios: AutoBeTest.IScenario[][] = await Promise.all(
50
- matrix.map(async (e) => {
51
- const rows: AutoBeTest.IScenario[] = await divideAndConquer(
52
- ctx,
53
- e,
54
- endpoints,
55
- files,
56
- 3,
57
- (count) => {
58
- completed += count;
59
- },
60
- );
61
- ctx.dispatch({
62
- type: "testScenario",
63
- scenarios: rows,
64
- total: rows.flatMap((el) => el.scenarios).length,
65
- step: ctx.state().test?.step ?? 0,
66
- completed,
67
- created_at: start.toISOString(),
68
- });
69
- return rows;
70
- }),
71
- );
33
+ const exclude: IAutoBeTestScenarioApplication.IScenarioGroup[] = [];
34
+ let include: AutoBeOpenApi.IOperation[] = Array.from(operations);
72
35
 
73
- return {
74
- type: "testScenario",
75
- scenarios: scenarios.flat(),
76
- total: scenarios.flat().flatMap((el) => el.scenarios).length,
77
- step: ctx.state().test?.step ?? 0,
78
- completed,
79
- created_at: start.toISOString(),
80
- };
81
- }
36
+ do {
37
+ const matrix = divideArray({ array: include, capacity: 30 });
82
38
 
83
- async function divideAndConquer<Model extends ILlmSchema.Model>(
84
- ctx: AutoBeContext<Model>,
85
- endpoints: AutoBeOpenApi.IEndpoint[],
86
- allEndpoints: AutoBeOpenApi.IEndpoint[],
87
- files: Record<string, string>,
88
- retry: number,
89
- progress: (completed: number) => void,
90
- ): Promise<AutoBeTest.IScenario[]> {
91
- const remained: HashSet<AutoBeOpenApi.IEndpoint> = new HashSet(
92
- endpoints,
93
- OpenApiEndpointComparator.hashCode,
94
- OpenApiEndpointComparator.equals,
95
- );
96
- const scenarios: HashMap<AutoBeOpenApi.IEndpoint, AutoBeTest.Scenario[]> =
97
- new HashMap(
98
- OpenApiEndpointComparator.hashCode,
99
- OpenApiEndpointComparator.equals,
100
- );
101
- for (let i: number = 0; i < retry; ++i) {
102
- if (remained.empty() === true || scenarios.size() >= endpoints.length)
103
- break;
104
- const before: number = scenarios.size();
105
- const newbie: AutoBeTest.IScenario[] = await process(
106
- ctx,
107
- Array.from(remained),
108
- allEndpoints,
109
- files,
39
+ await Promise.all(
40
+ matrix.map(async (_include) => {
41
+ exclude.push(
42
+ ...(await execute(
43
+ ctx,
44
+ operations,
45
+ _include,
46
+ exclude.map((x) => x.endpoint),
47
+ )),
48
+ );
49
+ }),
110
50
  );
111
- for (const item of newbie) {
112
- scenarios.set(item.endpoint, item.scenarios);
113
- remained.erase(item.endpoint);
114
- }
115
- if (scenarios.size() - before !== 0) progress(scenarios.size() - before);
116
- }
117
- return Array.from(scenarios.toJSON()).map((it) => ({
118
- endpoint: it.first,
119
- scenarios: it.second,
120
- }));
51
+
52
+ include = include.filter((op) => {
53
+ if (
54
+ exclude.some(
55
+ (pg) =>
56
+ pg.endpoint.method === op.method && pg.endpoint.path === op.path,
57
+ )
58
+ ) {
59
+ return false;
60
+ }
61
+ return true;
62
+ });
63
+ } while (include.length > 0);
64
+
65
+ return {
66
+ type: "testScenario",
67
+ step: ctx.state().analyze?.step ?? 0,
68
+ scenarios: exclude.flatMap((pg) => {
69
+ return pg.scenarios.map((plan) => {
70
+ return {
71
+ endpoint: pg.endpoint,
72
+ draft: plan.draft,
73
+ functionName: plan.functionName,
74
+ dependencies: plan.dependsOn,
75
+ } satisfies AutoBeTestScenario;
76
+ });
77
+ }),
78
+ created_at: new Date().toISOString(),
79
+ } as AutoBeTestScenarioEvent;
121
80
  }
122
81
 
123
- async function process<Model extends ILlmSchema.Model>(
82
+ const execute = async <Model extends ILlmSchema.Model>(
124
83
  ctx: AutoBeContext<Model>,
125
- endpoints: AutoBeOpenApi.IEndpoint[],
126
- allEndpoints: AutoBeOpenApi.IEndpoint[],
127
- files: Record<string, string>,
128
- ): Promise<AutoBeTest.IScenario[]> {
129
- const pointer: IPointer<AutoBeTest.IScenario[] | null> = {
130
- value: null,
84
+ ops: AutoBeOpenApi.IOperation[],
85
+ include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
86
+ exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
87
+ ) => {
88
+ const pointer: IPointer<IAutoBeTestScenarioApplication.IScenarioGroup[]> = {
89
+ value: [],
131
90
  };
132
-
133
- const agentica = new MicroAgentica({
91
+ const agentica: MicroAgentica<Model> = new MicroAgentica({
134
92
  model: ctx.model,
135
93
  vendor: ctx.vendor,
136
94
  config: {
137
- ...(ctx.config ?? { locale: "en-US" }),
138
- systemPrompt: {
139
- describe: () => {
140
- return "Answer only 'completion' or 'failure'.";
141
- },
95
+ ...(ctx.config ?? {}),
96
+ executor: {
97
+ describe: null,
142
98
  },
143
99
  },
144
100
  tokenUsage: ctx.usage(),
145
- histories: [
146
- ...transformTestScenarioHistories(ctx.state(), allEndpoints, files),
147
- ],
101
+ histories: createHistoryProperties(ops, include, exclude),
148
102
  controllers: [
149
103
  createApplication({
150
104
  model: ctx.model,
151
105
  build: (next) => {
152
106
  pointer.value ??= [];
153
- pointer.value.push(...next.scenarios);
107
+ pointer.value.push(...next.scenarioGroups);
154
108
  },
155
109
  }),
156
110
  ],
157
111
  });
158
112
  enforceToolCall(agentica);
159
113
 
160
- await agentica.conversate(
161
- [
162
- "Make User Scenarios for below endpoints:",
114
+ await agentica.conversate(`create test scenarios.`);
115
+ if (pointer.value.length === 0) {
116
+ throw new Error("Failed to create test plans.");
117
+ }
118
+
119
+ return pointer.value;
120
+ };
121
+
122
+ const createHistoryProperties = (
123
+ operations: AutoBeOpenApi.IOperation[],
124
+ include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
125
+ exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
126
+ ) => [
127
+ {
128
+ id: v4(),
129
+ created_at: new Date().toISOString(),
130
+ type: "systemMessage",
131
+ text: AutoBeSystemPromptConstant.TEST_SCENARIO,
132
+ } satisfies IAgenticaHistoryJson.ISystemMessage,
133
+ {
134
+ id: v4(),
135
+ created_at: new Date().toISOString(),
136
+ type: "systemMessage",
137
+ text: [
138
+ "Below are the full operations. Please refer to this.",
139
+ "Your role is to draft all test cases for each given Operation.",
140
+ "It is also permissible to write multiple test codes on a single endpoint.",
141
+ "However, rather than meaningless tests, business logic tests should be written and an E2E test situation should be assumed.",
163
142
  "",
164
143
  "```json",
165
- JSON.stringify(endpoints, null, 2),
144
+ JSON.stringify(
145
+ operations.map((el) => ({
146
+ path: el.path,
147
+ method: el.method,
148
+ summary: el.summary,
149
+ })),
150
+ ),
166
151
  "```",
167
152
  ].join("\n"),
168
- );
169
- if (pointer.value === null) throw new Error("Failed to make scenarios.");
170
- return pointer.value;
171
- }
153
+ } satisfies IAgenticaHistoryJson.ISystemMessage,
154
+ {
155
+ id: v4(),
156
+ created_at: new Date().toISOString(),
157
+ type: "systemMessage",
158
+ text: [
159
+ "# Included in Test Plan",
160
+ include
161
+ .map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
162
+ .join("\n"),
163
+ "",
164
+ "# Excluded from Test Plan",
165
+ "These are the endpoints that have already been used in test codes generated as part of a plan group.",
166
+ "These endpoints do not need to be tested again.",
167
+ "However, it is allowed to reference or depend on these endpoints when writing test codes for other purposes.",
168
+ exclude
169
+ .map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
170
+ .join("\n"),
171
+ ].join("\n"),
172
+ } satisfies IAgenticaHistoryJson.ISystemMessage,
173
+ ];
172
174
 
173
175
  function createApplication<Model extends ILlmSchema.Model>(props: {
174
176
  model: Model;
175
- build: (next: IMakeScenarioProps) => void;
177
+ build: (next: IAutoBeTestScenarioApplication.IProps) => void;
176
178
  }): IAgenticaController.IClass<Model> {
177
179
  assertSchemaModel(props.model);
178
180
 
179
181
  const application: ILlmApplication<Model> = collection[
180
182
  props.model
181
183
  ] as unknown as ILlmApplication<Model>;
184
+
185
+ application.functions[0].validate = (next: unknown): IValidation => {
186
+ const result: IValidation<IAutoBeTestScenarioApplication.IProps> =
187
+ typia.validate<IAutoBeTestScenarioApplication.IProps>(next);
188
+ if (result.success === false) return result;
189
+
190
+ const errors: IValidation.IError[] = [];
191
+ result.data.scenarioGroups.forEach((pg, i, arr) => {
192
+ arr.forEach((target, j) => {
193
+ if (
194
+ i !== j &&
195
+ target.endpoint.method === pg.endpoint.method &&
196
+ target.endpoint.path === pg.endpoint.path
197
+ ) {
198
+ if (
199
+ !errors.some(
200
+ (el) =>
201
+ el.path !== `planGroups[${j}].path` &&
202
+ el.value !== target.endpoint.path,
203
+ )
204
+ ) {
205
+ errors.push({
206
+ path: `planGroups[${j}].path`,
207
+ expected: `planGroup's {method + path} cannot duplicated.`,
208
+ value: target.endpoint.path,
209
+ });
210
+ }
211
+
212
+ if (
213
+ !errors.some(
214
+ (el) =>
215
+ el.path !== `planGroups[${j}].method` &&
216
+ el.value !== target.endpoint.method,
217
+ )
218
+ ) {
219
+ errors.push({
220
+ path: `planGroups[${j}].method`,
221
+ expected: `planGroup's {method + path} cannot duplicated.`,
222
+ value: target.endpoint.method,
223
+ });
224
+ }
225
+ }
226
+ });
227
+ });
228
+
229
+ if (errors.length !== 0) {
230
+ console.log(JSON.stringify(errors, null, 2), "errors");
231
+ return {
232
+ success: false,
233
+ errors,
234
+ data: next,
235
+ };
236
+ }
237
+
238
+ return result;
239
+ };
182
240
  return {
183
241
  protocol: "class",
184
- name: "Make User Scenarios",
242
+ name: "Make test plans",
185
243
  application,
186
244
  execute: {
187
245
  makeScenario: (next) => {
188
246
  props.build(next);
189
247
  },
190
- } satisfies IApplication,
248
+ } satisfies IAutoBeTestScenarioApplication,
191
249
  };
192
250
  }
193
251
 
194
252
  const claude = typia.llm.application<
195
- IApplication,
253
+ IAutoBeTestScenarioApplication,
196
254
  "claude",
197
255
  {
198
256
  reference: true;
@@ -200,7 +258,7 @@ const claude = typia.llm.application<
200
258
  >();
201
259
  const collection = {
202
260
  chatgpt: typia.llm.application<
203
- IApplication,
261
+ IAutoBeTestScenarioApplication,
204
262
  "chatgpt",
205
263
  { reference: true }
206
264
  >(),
@@ -208,19 +266,5 @@ const collection = {
208
266
  llama: claude,
209
267
  deepseek: claude,
210
268
  "3.1": claude,
211
- "3.0": typia.llm.application<IApplication, "3.0">(),
269
+ "3.0": typia.llm.application<IAutoBeTestScenarioApplication, "3.0">(),
212
270
  };
213
-
214
- interface IApplication {
215
- /**
216
- * Make user scenarios for the given endpoints.
217
- *
218
- * @param props Properties containing the endpoints and user scenarios.
219
- */
220
- makeScenario(props: IMakeScenarioProps): void;
221
- }
222
-
223
- interface IMakeScenarioProps {
224
- /** Array of user scenarios. */
225
- scenarios: AutoBeTest.IScenario[];
226
- }
@@ -1,5 +1,5 @@
1
1
  import { IAgenticaController, MicroAgentica } from "@agentica/core";
2
- import { AutoBeTest, AutoBeTestProgressEvent } from "@autobe/interface";
2
+ import { AutoBeTestScenario, AutoBeTestWriteEvent } from "@autobe/interface";
3
3
  import { ILlmApplication, ILlmSchema } from "@samchon/openapi";
4
4
  import { IPointer } from "tstl";
5
5
  import typia from "typia";
@@ -7,28 +7,29 @@ import typia from "typia";
7
7
  import { AutoBeContext } from "../../context/AutoBeContext";
8
8
  import { assertSchemaModel } from "../../context/assertSchemaModel";
9
9
  import { enforceToolCall } from "../../utils/enforceToolCall";
10
- import { transformTestProgressHistories } from "./transformTestProgressHistories";
10
+ import { compileTestScenario } from "./compileTestScenario";
11
+ import { IAutoBeTestScenarioArtifacts } from "./structures/IAutoBeTestScenarioArtifacts";
12
+ import { transformTestWriteHistories } from "./transformTestWriteHistories";
11
13
 
12
- export async function orchestrateTestProgress<Model extends ILlmSchema.Model>(
14
+ export async function orchestrateTestWrite<Model extends ILlmSchema.Model>(
13
15
  ctx: AutoBeContext<Model>,
14
- scenarios: AutoBeTest.Scenario[],
15
- ): Promise<AutoBeTestProgressEvent[]> {
16
+ scenarios: AutoBeTestScenario[],
17
+ ): Promise<AutoBeTestWriteEvent[]> {
16
18
  const start: Date = new Date();
17
19
  let complete: number = 0;
18
20
 
19
- const events: AutoBeTestProgressEvent[] = await Promise.all(
21
+ const events: AutoBeTestWriteEvent[] = await Promise.all(
20
22
  /**
21
- * Generate test code for each scenario. Maps through scenarios array to
22
- * create individual test code implementations. Each scenario is processed
23
- * to generate corresponding test code and progress events.
23
+ * Generate test code for each scenario. Maps through plans array to create
24
+ * individual test code implementations. Each scenario is processed to
25
+ * generate corresponding test code and progress events.
24
26
  */
25
27
  scenarios.map(async (scenario) => {
26
28
  const code: ICreateTestCodeProps = await process(ctx, scenario);
27
-
28
- const event: AutoBeTestProgressEvent = {
29
- type: "testProgress",
29
+ const event: AutoBeTestWriteEvent = {
30
+ type: "testWrite",
30
31
  created_at: start.toISOString(),
31
- filename: `${code.domain}/${scenario.functionName}.ts`,
32
+ filename: `test/features/api/${code.domain}/${scenario.functionName}.ts`,
32
33
  content: code.content,
33
34
  completed: ++complete,
34
35
  total: scenarios.length,
@@ -54,27 +55,15 @@ export async function orchestrateTestProgress<Model extends ILlmSchema.Model>(
54
55
  */
55
56
  async function process<Model extends ILlmSchema.Model>(
56
57
  ctx: AutoBeContext<Model>,
57
- scenario: AutoBeTest.Scenario,
58
+ scenario: AutoBeTestScenario,
58
59
  ): Promise<ICreateTestCodeProps> {
59
60
  const pointer: IPointer<ICreateTestCodeProps | null> = {
60
61
  value: null,
61
62
  };
62
-
63
- const apiFiles = Object.entries(ctx.state().interface?.files ?? {})
64
- .filter(([filename]) => {
65
- return filename.startsWith("src/api/");
66
- })
67
- .reduce<Record<string, string>>((acc, [filename, content]) => {
68
- return Object.assign(acc, { [filename]: content });
69
- }, {});
70
-
71
- const dtoFiles = Object.entries(ctx.state().interface?.files ?? {})
72
- .filter(([filename]) => {
73
- return filename.startsWith("src/api/structures/");
74
- })
75
- .reduce<Record<string, string>>((acc, [filename, content]) => {
76
- return Object.assign(acc, { [filename]: content });
77
- }, {});
63
+ const artifacts: IAutoBeTestScenarioArtifacts = await compileTestScenario(
64
+ ctx,
65
+ scenario,
66
+ );
78
67
 
79
68
  const agentica = new MicroAgentica({
80
69
  model: ctx.model,
@@ -82,7 +71,10 @@ async function process<Model extends ILlmSchema.Model>(
82
71
  config: {
83
72
  ...(ctx.config ?? {}),
84
73
  },
85
- histories: transformTestProgressHistories(apiFiles, dtoFiles),
74
+ histories: transformTestWriteHistories({
75
+ scenario,
76
+ artifacts,
77
+ }),
86
78
  controllers: [
87
79
  createApplication({
88
80
  model: ctx.model,
@@ -91,18 +83,11 @@ async function process<Model extends ILlmSchema.Model>(
91
83
  },
92
84
  }),
93
85
  ],
86
+ tokenUsage: ctx.usage(),
94
87
  });
95
88
  enforceToolCall(agentica);
96
89
 
97
- await agentica.conversate(
98
- [
99
- "Create test code for below scenario:",
100
- "",
101
- "```json",
102
- JSON.stringify(scenario, null, 2),
103
- "```",
104
- ].join("\n"),
105
- );
90
+ await agentica.conversate("Create e2e test functions.");
106
91
  if (pointer.value === null) throw new Error("Failed to create test code.");
107
92
  return pointer.value;
108
93
  }
@@ -178,7 +163,7 @@ interface ICreateTestCodeProps {
178
163
  * #### Execution Strategy
179
164
  *
180
165
  * - Outline step-by-step test execution flow
181
- * - Plan error handling and exception scenarios
166
+ * - Plan error handling and exception plans
182
167
  * - Define cleanup and teardown procedures
183
168
  * - Identify dependencies and prerequisites
184
169
  *
@@ -188,12 +173,12 @@ interface ICreateTestCodeProps {
188
173
  * 1. Prepare valid article data with required fields
189
174
  * 2. Execute POST request to create article
190
175
  * 3. Validate response structure and data integrity
191
- * 4. Test error scenarios (missing fields, invalid data)
176
+ * 4. Test error plans (missing fields, invalid data)
192
177
  * 5. Verify database state changes
193
- * 6. Reconsider the plan if it doesn't follow the Test Generation
178
+ * 6. Reconsider the scenario if it doesn't follow the Test Generation
194
179
  * Guildelines.
195
180
  */
196
- plan: string;
181
+ scenario: string;
197
182
 
198
183
  /**
199
184
  * Functional domain classification for test organization.
@@ -0,0 +1,132 @@
1
+ import { AutoBeOpenApi } from "@autobe/interface";
2
+
3
+ export interface IAutoBeTestScenarioApplication {
4
+ /**
5
+ * Make test scenarios for the given endpoints.
6
+ *
7
+ * @param props Properties containing the endpoints and test scenarios.
8
+ */
9
+ makeScenario(props: IAutoBeTestScenarioApplication.IProps): void;
10
+ }
11
+
12
+ export namespace IAutoBeTestScenarioApplication {
13
+ export interface IProps {
14
+ /** Array of test scenario groups. */
15
+ scenarioGroups: IAutoBeTestScenarioApplication.IScenarioGroup[];
16
+ }
17
+
18
+ export interface IScenarioGroup {
19
+ /** Target API endpoint to test. */
20
+ endpoint: AutoBeOpenApi.IEndpoint;
21
+
22
+ /** Array of test scenarios. */
23
+ scenarios: IScenario[];
24
+ }
25
+
26
+ /**
27
+ * Represents a test scenario for a single API operation.
28
+ *
29
+ * This interface extends `AutoBeOpenApi.IEndpoint`, inheriting its HTTP
30
+ * method and path information, and adds two key properties:
31
+ *
32
+ * - `draft`: A free-form, human-readable test scenario description for the API
33
+ * endpoint.
34
+ * - `dependsOn`: A list of other API endpoints that must be invoked beforehand
35
+ * in order to prepare the context for this test. Each dependency includes
36
+ * the purpose of the dependency.
37
+ *
38
+ * This structure is intended to help organize test specifications for complex
39
+ * workflows and ensure that all prerequisites are explicitly declared.
40
+ */
41
+ export interface IScenario {
42
+ /**
43
+ * A detailed natural language description of how this API endpoint should
44
+ * be tested. This should include both successful and failure scenarios,
45
+ * business rule validations, edge cases, and any sequence of steps
46
+ * necessary to perform the test. A subsequent agent will use this draft to
47
+ * generate multiple test scenarios.
48
+ */
49
+ draft: string;
50
+
51
+ /**
52
+ * Descriptive function name derived from the user scenario.
53
+ *
54
+ * The function name serves as a concise, technical identifier that clearly
55
+ * represents the specific user scenario being described. It should be
56
+ * immediately understandable and directly correspond to the user situation
57
+ * without requiring additional context.
58
+ *
59
+ * ## Naming Convention
60
+ *
61
+ * - Must start with `test_` prefix (mandatory requirement)
62
+ * - Use snake_case formatting throughout
63
+ * - Include the primary user action (create, get, update, delete, list, etc.)
64
+ * - Specify the target resource (user, product, order, profile, etc.)
65
+ * - Add scenario-specific context (valid_data, invalid_email, not_found,
66
+ * etc.)
67
+ *
68
+ * ## Content Structure
69
+ *
70
+ * Function names should follow this pattern:
71
+ * `test_[user_action]_[resource]_[scenario_context]`
72
+ *
73
+ * Where:
74
+ *
75
+ * - `user_action`: What the user is trying to do
76
+ * - `resource`: What the user is interacting with
77
+ * - `scenario_context`: The specific situation or condition
78
+ *
79
+ * ## User-Focused Examples
80
+ *
81
+ * - `test_create_user_profile_with_complete_information` - User providing all
82
+ * available profile data
83
+ * - `test_retrieve_user_profile_when_profile_exists` - User accessing their
84
+ * existing profile
85
+ * - `test_update_user_email_with_valid_new_address` - User changing their
86
+ * email to a valid new one
87
+ * - `test_delete_user_account_when_user_lacks_permission` - User attempting
88
+ * account deletion without authorization
89
+ * - `test_search_user_profiles_with_pagination_preferences` - User browsing
90
+ * profiles with specific pagination
91
+ *
92
+ * ## Clarity Guidelines
93
+ *
94
+ * - Prioritize clarity over brevity
95
+ * - Avoid technical jargon or implementation terms
96
+ * - Use terminology that reflects user perspective
97
+ * - Ensure the name alone conveys the user's intent
98
+ * - Make it understandable to non-technical stakeholders
99
+ * - Keep consistent with user scenario description
100
+ *
101
+ * ## Single Endpoint Alignment
102
+ *
103
+ * Function names must reflect scenarios that:
104
+ *
105
+ * - Accomplish user goals through this single endpoint only
106
+ * - Don't imply dependency on other API operations
107
+ * - Represent complete user interactions
108
+ */
109
+ functionName: string;
110
+
111
+ /**
112
+ * A list of other API endpoints that must be executed before this test
113
+ * scenario. This helps express dependencies such as data creation or
114
+ * authentication steps required to reach the intended test state.
115
+ */
116
+ dependsOn: IDependsOn[];
117
+ }
118
+
119
+ export interface IDependsOn {
120
+ /** Target API endpoint that must be executed before the main operation. */
121
+ endpoint: AutoBeOpenApi.IEndpoint;
122
+
123
+ /**
124
+ * A concise exscenarioation of why this API call is required before
125
+ * executing the test for the main operation.
126
+ *
127
+ * Example: "Creates a category so that a product can be linked to it during
128
+ * creation."
129
+ */
130
+ purpose: string;
131
+ }
132
+ }