@autobe/agent 0.9.0 → 0.9.2

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 (62) hide show
  1. package/lib/AutoBeAgent.js +7 -1
  2. package/lib/AutoBeAgent.js.map +1 -1
  3. package/lib/constants/AutoBeSystemPromptConstant.d.ts +5 -3
  4. package/lib/constants/AutoBeSystemPromptConstant.js.map +1 -1
  5. package/lib/context/IAutoBeApplicationProps.d.ts +0 -61
  6. package/lib/factory/createAutoBeApplication.js +15 -135
  7. package/lib/factory/createAutoBeApplication.js.map +1 -1
  8. package/lib/index.mjs +1054 -1037
  9. package/lib/index.mjs.map +1 -1
  10. package/lib/orchestrate/analyze/orchestrateAnalyze.js +4 -30
  11. package/lib/orchestrate/analyze/orchestrateAnalyze.js.map +1 -1
  12. package/lib/orchestrate/interface/orchestrateInterface.js +9 -3
  13. package/lib/orchestrate/interface/orchestrateInterface.js.map +1 -1
  14. package/lib/orchestrate/test/compileTestScenario.d.ts +5 -0
  15. package/lib/orchestrate/test/compileTestScenario.js +57 -0
  16. package/lib/orchestrate/test/compileTestScenario.js.map +1 -0
  17. package/lib/orchestrate/test/filterTestFileName.d.ts +1 -0
  18. package/lib/orchestrate/test/filterTestFileName.js +13 -0
  19. package/lib/orchestrate/test/filterTestFileName.js.map +1 -0
  20. package/lib/orchestrate/test/orchestrateTest.js +6 -3
  21. package/lib/orchestrate/test/orchestrateTest.js.map +1 -1
  22. package/lib/orchestrate/test/orchestrateTestCorrect.d.ts +2 -2
  23. package/lib/orchestrate/test/orchestrateTestCorrect.js +172 -87
  24. package/lib/orchestrate/test/orchestrateTestCorrect.js.map +1 -1
  25. package/lib/orchestrate/test/orchestrateTestScenario.js +98 -83
  26. package/lib/orchestrate/test/orchestrateTestScenario.js.map +1 -1
  27. package/lib/orchestrate/test/orchestrateTestWrite.d.ts +4 -0
  28. package/lib/orchestrate/test/{orchestrateTestProgress.js → orchestrateTestWrite.js} +27 -54
  29. package/lib/orchestrate/test/orchestrateTestWrite.js.map +1 -0
  30. package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.d.ts +18 -20
  31. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.d.ts +7 -0
  32. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.js +3 -0
  33. package/lib/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.js.map +1 -0
  34. package/lib/orchestrate/test/transformTestCorrectHistories.d.ts +2 -2
  35. package/lib/orchestrate/test/transformTestCorrectHistories.js +38 -16
  36. package/lib/orchestrate/test/transformTestCorrectHistories.js.map +1 -1
  37. package/lib/orchestrate/test/transformTestWriteHistories.d.ts +7 -0
  38. package/lib/orchestrate/test/transformTestWriteHistories.js +59 -0
  39. package/lib/orchestrate/test/transformTestWriteHistories.js.map +1 -0
  40. package/lib/structures/IAutoBeProps.d.ts +12 -1
  41. package/package.json +4 -5
  42. package/src/AutoBeAgent.ts +14 -2
  43. package/src/constants/AutoBeSystemPromptConstant.ts +5 -3
  44. package/src/context/IAutoBeApplicationProps.ts +0 -62
  45. package/src/orchestrate/analyze/orchestrateAnalyze.ts +4 -34
  46. package/src/orchestrate/interface/orchestrateInterface.ts +7 -0
  47. package/src/orchestrate/test/compileTestScenario.ts +64 -0
  48. package/src/orchestrate/test/filterTestFileName.ts +9 -0
  49. package/src/orchestrate/test/orchestrateTest.ts +15 -9
  50. package/src/orchestrate/test/orchestrateTestCorrect.ts +288 -128
  51. package/src/orchestrate/test/orchestrateTestScenario.ts +23 -6
  52. package/src/orchestrate/test/{orchestrateTestProgress.ts → orchestrateTestWrite.ts} +56 -87
  53. package/src/orchestrate/test/structures/IAutoBeTestScenarioApplication.ts +18 -20
  54. package/src/orchestrate/test/structures/IAutoBeTestScenarioArtifacts.ts +8 -0
  55. package/src/orchestrate/test/transformTestCorrectHistories.ts +41 -17
  56. package/src/orchestrate/test/{transformTestProgressHistories.ts → transformTestWriteHistories.ts} +21 -10
  57. package/src/structures/IAutoBeProps.ts +17 -1
  58. package/lib/orchestrate/test/orchestrateTestProgress.d.ts +0 -5
  59. package/lib/orchestrate/test/orchestrateTestProgress.js.map +0 -1
  60. package/lib/orchestrate/test/transformTestProgressHistories.d.ts +0 -8
  61. package/lib/orchestrate/test/transformTestProgressHistories.js +0 -47
  62. package/lib/orchestrate/test/transformTestProgressHistories.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { IAgenticaController, MicroAgentica } from "@agentica/core";
2
2
  import {
3
- AutoBeOpenApi,
4
- AutoBeTestScenarioEvent,
3
+ AutoBeTestFile,
4
+ AutoBeTestScenario,
5
5
  AutoBeTestValidateEvent,
6
6
  AutoBeTestWriteEvent,
7
7
  IAutoBeTypeScriptCompilerResult,
@@ -14,59 +14,57 @@ import { AutoBeContext } from "../../context/AutoBeContext";
14
14
  import { assertSchemaModel } from "../../context/assertSchemaModel";
15
15
  import { randomBackoffRetry } from "../../utils/backoffRetry";
16
16
  import { enforceToolCall } from "../../utils/enforceToolCall";
17
- import { filterDocument } from "./orchestrateTestProgress";
17
+ import { compileTestScenario } from "./compileTestScenario";
18
+ import { filterTestFileName } from "./filterTestFileName";
19
+ import { IAutoBeTestScenarioArtifacts } from "./structures/IAutoBeTestScenarioArtifacts";
18
20
  import { transformTestCorrectHistories } from "./transformTestCorrectHistories";
19
21
 
20
22
  export async function orchestrateTestCorrect<Model extends ILlmSchema.Model>(
21
23
  ctx: AutoBeContext<Model>,
22
24
  codes: AutoBeTestWriteEvent[],
23
- scenarios: AutoBeTestScenarioEvent.IScenario[],
25
+ scenarios: AutoBeTestScenario[],
24
26
  life: number = 4,
25
27
  ): Promise<AutoBeTestValidateEvent> {
26
- const scenarioMap: Map<string, AutoBeTestScenarioEvent.IScenario> = new Map();
27
- codes.forEach(({ filename }, index) => {
28
- scenarioMap.set(filename, scenarios[index]);
29
- });
28
+ const files: AutoBeTestFile[] = codes.map(
29
+ ({ filename, content }, index): AutoBeTestFile => {
30
+ const scenario: AutoBeTestScenario = scenarios[index];
31
+ return { location: filename, content, scenario };
32
+ },
33
+ );
30
34
 
31
35
  // 1) Build map of new test files from progress events
32
- const testFiles: Record<string, string> = codes
33
- .map(({ filename, content }) => {
34
- return {
35
- [`test/features/api/${filename}`]: content,
36
- };
37
- })
38
- .reduce<Record<string, string>>((acc, cur) => Object.assign(acc, cur), {});
36
+ const testFiles: Record<string, string> = Object.fromEntries(
37
+ codes.map((c) => [c.filename, c.content]),
38
+ );
39
39
 
40
40
  // 2) Keep only files outside the test directory from current state
41
- const retainedFiles: Record<string, string> = Object.entries(
42
- ctx.state().interface?.files ?? {},
43
- )
44
- .filter(([filename]) => {
45
- return !filename.startsWith("test/features/api");
46
- })
47
- .map(([filename, content]) => {
48
- return { [filename]: content };
49
- })
50
- .reduce<Record<string, string>>((acc, cur) => Object.assign(acc, cur), {});
41
+ const retainedFiles: Record<string, string> = Object.fromEntries(
42
+ Object.entries(ctx.state().interface?.files ?? {}).filter(([key]) =>
43
+ filterTestFileName(key),
44
+ ),
45
+ );
51
46
 
52
47
  // 3) Merge and filter: keep .ts/.json, drop anything under "benchmark"
48
+ const external = async (
49
+ location: string,
50
+ ): Promise<Record<string, string>> => {
51
+ const content: string | undefined =
52
+ await ctx.compiler.typescript.getExternal(location);
53
+ if (content === undefined) throw new Error(`File not found: ${location}`);
54
+ return { [location]: content };
55
+ };
53
56
  const mergedFiles: Record<string, string> = {
54
57
  ...retainedFiles,
55
58
  ...testFiles,
59
+ ...(await external("node_modules/@nestia/e2e/lib/TestValidator.d.ts")),
60
+ ...(await external("node_modules/@nestia/fetcher/lib/IConnection.d.ts")),
56
61
  };
57
- const files: Record<string, string> = Object.fromEntries(
58
- Object.entries(mergedFiles).filter(
59
- ([filename]) =>
60
- (filename.endsWith(".ts") && !filename.startsWith("test/benchmark/")) ||
61
- filename.endsWith(".json"),
62
- ),
63
- );
64
62
 
65
63
  // 4) Ask the LLM to correct the filtered file set
66
64
  const response: AutoBeTestValidateEvent = await step(
67
65
  ctx,
66
+ mergedFiles,
68
67
  files,
69
- scenarioMap,
70
68
  life,
71
69
  );
72
70
 
@@ -74,7 +72,17 @@ export async function orchestrateTestCorrect<Model extends ILlmSchema.Model>(
74
72
  const event: AutoBeTestValidateEvent = {
75
73
  ...response,
76
74
  type: "testValidate",
77
- files: { ...mergedFiles, ...response.files },
75
+ files: [
76
+ ...Object.entries(mergedFiles).map(
77
+ ([filename, content]): AutoBeTestFile => {
78
+ return {
79
+ location: filename,
80
+ content,
81
+ };
82
+ },
83
+ ),
84
+ ...response.files,
85
+ ],
78
86
  };
79
87
  return event;
80
88
  }
@@ -89,29 +97,35 @@ export async function orchestrateTestCorrect<Model extends ILlmSchema.Model>(
89
97
  * all generated test files are syntactically correct and compilable.
90
98
  *
91
99
  * @param ctx AutoBe context object
92
- * @param files Map of files to compile (filename: content)
100
+ * @param entireFiles Map of all files to compile (filename: content)
101
+ * @param testFiles Map of files to compile (filename: content)
93
102
  * @param life Number of remaining retry attempts
94
103
  * @returns Event object containing successful compilation result and modified
95
104
  * files
96
105
  */
97
106
  async function step<Model extends ILlmSchema.Model>(
98
107
  ctx: AutoBeContext<Model>,
99
- files: Record<string, string>,
100
- scenarioMap: Map<string, AutoBeTestScenarioEvent.IScenario>,
108
+ entireFiles: Record<string, string>,
109
+ testFiles: AutoBeTestFile[],
101
110
  life: number,
102
111
  ): Promise<AutoBeTestValidateEvent> {
103
112
  // COMPILE TEST CODE
104
-
105
113
  const result: IAutoBeTypeScriptCompilerResult =
106
114
  await ctx.compiler.typescript.compile({
107
- files,
115
+ files: {
116
+ ...entireFiles,
117
+ ...testFiles
118
+ .map((el) => ({ [el.location]: el.content }))
119
+ .reduce((acc, cur) => Object.assign(acc, cur), {}),
120
+ },
108
121
  });
122
+
109
123
  if (result.type === "success") {
110
124
  // SUCCESS
111
125
  return {
112
126
  type: "testValidate",
113
127
  created_at: new Date().toISOString(),
114
- files,
128
+ files: testFiles,
115
129
  result,
116
130
  step: ctx.state().interface?.step ?? 0,
117
131
  };
@@ -122,7 +136,7 @@ async function step<Model extends ILlmSchema.Model>(
122
136
  ctx.dispatch({
123
137
  type: "testValidate",
124
138
  created_at: new Date().toISOString(),
125
- files,
139
+ files: testFiles,
126
140
  result,
127
141
  step: ctx.state().interface?.step ?? 0,
128
142
  });
@@ -151,7 +165,7 @@ async function step<Model extends ILlmSchema.Model>(
151
165
  return {
152
166
  type: "testValidate",
153
167
  created_at: new Date().toISOString(),
154
- files,
168
+ files: testFiles,
155
169
  result: {
156
170
  ...result,
157
171
  type: "success",
@@ -164,7 +178,7 @@ async function step<Model extends ILlmSchema.Model>(
164
178
  ctx.dispatch({
165
179
  type: "testValidate",
166
180
  created_at: new Date().toISOString(),
167
- files,
181
+ files: testFiles,
168
182
  result,
169
183
  step: ctx.state().interface?.step ?? 0,
170
184
  });
@@ -173,44 +187,66 @@ async function step<Model extends ILlmSchema.Model>(
173
187
  return {
174
188
  type: "testValidate",
175
189
  created_at: new Date().toISOString(),
176
- files,
190
+ files: testFiles,
177
191
  result,
178
192
  step: ctx.state().interface?.step ?? 0,
179
193
  };
180
194
 
181
195
  // VALIDATION FAILED
182
- const validate: [string, string][] = await Promise.all(
183
- Object.entries(diagnostics).map(async ([filename, d]) => {
184
- const scenario: AutoBeTestScenarioEvent.IScenario =
185
- scenarioMap.get(filename)!;
186
- const code: string = files[filename];
187
- const response: ICorrectTestFunctionProps = await process(
188
- ctx,
189
- d,
190
- code,
191
- scenario,
192
- );
193
- ctx.dispatch({
194
- type: "testCorrect",
195
- created_at: new Date().toISOString(),
196
- files: { ...files, [filename]: response.content },
197
- result,
198
- solution: response.solution,
199
- think_without_compile_error: response.think_without_compile_error,
200
- think_again_with_compile_error: response.think_again_with_compile_error,
201
- step: ctx.state().interface?.step ?? 0,
202
- });
203
-
204
- // Return [filename, modified code]
205
- return [filename, response.content];
206
- }),
196
+ const validatedFiles: AutoBeTestFile[] = await Promise.all(
197
+ Object.entries(diagnostics).map(
198
+ async ([filename, d]): Promise<AutoBeTestFile> => {
199
+ const file = testFiles.find((f) => f.location === filename);
200
+ const code: string = file?.content!;
201
+ const scenario = file?.scenario!;
202
+
203
+ const response: ICorrectTestFunctionProps = await process(
204
+ ctx,
205
+ d,
206
+ code,
207
+ scenario,
208
+ );
209
+ ctx.dispatch({
210
+ type: "testCorrect",
211
+ created_at: new Date().toISOString(),
212
+ files: { ...testFiles, [filename]: response.content },
213
+ result,
214
+ solution: response.solution,
215
+ think_without_compile_error: response.think_without_compile_error,
216
+ think_again_with_compile_error:
217
+ response.think_again_with_compile_error,
218
+ step: ctx.state().interface?.step ?? 0,
219
+ });
220
+
221
+ return {
222
+ location: filename,
223
+ content: response.content,
224
+ scenario: scenario,
225
+ };
226
+ },
227
+ ),
207
228
  );
208
229
 
209
- const newFiles: Record<string, string> = {
210
- ...files,
211
- ...Object.fromEntries(validate),
212
- };
213
- return step(ctx, newFiles, scenarioMap, life - 1);
230
+ return step(
231
+ ctx,
232
+ Object.entries(entireFiles)
233
+ .map(([filename, content]) => {
234
+ const overwritten = validatedFiles.find(
235
+ (el) => el.location === filename,
236
+ );
237
+ return overwritten
238
+ ? { [overwritten.location]: overwritten.content }
239
+ : {
240
+ [filename]: content,
241
+ };
242
+ })
243
+ .reduce((acc, cur) => Object.assign(acc, cur), {}),
244
+ testFiles.map((f) => {
245
+ const validated = validatedFiles.find((v) => v.location === f.location);
246
+ return validated ? validated : f;
247
+ }),
248
+ life - 1,
249
+ );
214
250
  }
215
251
 
216
252
  /**
@@ -227,32 +263,28 @@ async function process<Model extends ILlmSchema.Model>(
227
263
  ctx: AutoBeContext<Model>,
228
264
  diagnostics: IAutoBeTypeScriptCompilerResult.IDiagnostic[],
229
265
  code: string,
230
- scenario: AutoBeTestScenarioEvent.IScenario,
266
+ scenario: AutoBeTestScenario,
231
267
  ): Promise<ICorrectTestFunctionProps> {
232
268
  const pointer: IPointer<ICorrectTestFunctionProps | null> = {
233
269
  value: null,
234
270
  };
271
+ const artifacts: IAutoBeTestScenarioArtifacts = await compileTestScenario(
272
+ ctx,
273
+ scenario,
274
+ );
235
275
 
236
- let document: AutoBeOpenApi.IDocument | null = null;
237
- if (scenario) {
238
- document = filterDocument(scenario, ctx.state().interface!.document);
239
- }
240
-
241
- // const apiFiles = Object.entries(ctx.state().interface?.files ?? {})
242
- // .filter(([filename]) => {
243
- // return filename.startsWith("src/api/");
244
- // })
245
- // .reduce<Record<string, string>>((acc, [filename, content]) => {
246
- // return Object.assign(acc, { [filename]: content });
247
- // }, {});
248
-
249
- // const dtoFiles = Object.entries(ctx.state().interface?.files ?? {})
250
- // .filter(([filename]) => {
251
- // return filename.startsWith("src/api/structures/");
252
- // })
253
- // .reduce<Record<string, string>>((acc, [filename, content]) => {
254
- // return Object.assign(acc, { [filename]: content });
255
- // }, {});
276
+ const lines = code.split("\n").map((line, num, arr) => {
277
+ const start = arr
278
+ .slice(0, num)
279
+ .map((el) => el.length + 1)
280
+ .reduce((acc, cur) => acc + cur, 0);
281
+ return {
282
+ line: num + 1,
283
+ text: line,
284
+ start: start,
285
+ end: start + line.length + 1, // exclusive
286
+ };
287
+ });
256
288
 
257
289
  const agentica = new MicroAgentica({
258
290
  model: ctx.model,
@@ -260,7 +292,15 @@ async function process<Model extends ILlmSchema.Model>(
260
292
  config: {
261
293
  ...(ctx.config ?? {}),
262
294
  },
263
- histories: transformTestCorrectHistories(document),
295
+ histories: transformTestCorrectHistories(
296
+ code,
297
+ artifacts,
298
+ diagnostics.map((diagnostic) =>
299
+ diagnostic.start === undefined || diagnostic.length === undefined
300
+ ? ""
301
+ : formatDiagnostic(code, lines, diagnostic),
302
+ ),
303
+ ),
264
304
  controllers: [
265
305
  createApplication({
266
306
  model: ctx.model,
@@ -276,38 +316,7 @@ async function process<Model extends ILlmSchema.Model>(
276
316
  await randomBackoffRetry(async () => {
277
317
  await agentica.conversate(
278
318
  [
279
- "Fix the compilation error in the provided code.",
280
- "",
281
- "## Original Code",
282
- "```typescript",
283
- code,
284
- "```",
285
- "",
286
- diagnostics.map((diagnostic) => {
287
- if (diagnostic.start === undefined || diagnostic.length === undefined)
288
- return "";
289
-
290
- const checkDtoRegexp = `Cannot find module '@ORGANIZATION/template-api/lib/structures/IBbsArticleComment' or its corresponding type declarations.`;
291
- const [group] = [
292
- ...checkDtoRegexp.matchAll(
293
- /Cannot find module '(.*lib\/structures\/.*)'/g,
294
- ),
295
- ];
296
-
297
- const [_, filename] = group ?? [];
298
-
299
- return [
300
- "## Error Information",
301
- `- Position: Characters ${diagnostic.start} to ${diagnostic.start + diagnostic.length}`,
302
- `- Error Message: ${diagnostic.messageText}`,
303
- `- Problematic Code: \`${code.substring(diagnostic.start, diagnostic.start + diagnostic.length)}\``,
304
- filename
305
- ? `The type files located under **/lib/structures are declared in '@ORGANIZATION/PROJECT-api/lib/structures'.\n` +
306
- `Note: '@ORGANIZATION/PROJECT-api' must be written exactly as is and should not be replaced.\n`
307
- : "",
308
- ].join("\n");
309
- }),
310
- "## Instructions",
319
+ "# Instructions",
311
320
  "1. Focus on the specific error location and message",
312
321
  "2. Provide the corrected TypeScript code",
313
322
  "3. Ensure the fix resolves the compilation error",
@@ -317,9 +326,160 @@ async function process<Model extends ILlmSchema.Model>(
317
326
  );
318
327
  });
319
328
  if (pointer.value === null) throw new Error("Failed to modify test code.");
329
+
330
+ const typeReferences: string[] = Array.from(
331
+ new Set(
332
+ Object.keys(artifacts.document.components.schemas).map(
333
+ (key) => key.split(".")[0]!,
334
+ ),
335
+ ),
336
+ );
337
+
338
+ pointer.value.content = pointer.value.content
339
+ .replace(/^[ \t]*import\b[\s\S]*?;[ \t]*$/gm, "")
340
+ .trim();
341
+ pointer.value.content = [
342
+ `import { TestValidator } from "@nestia/e2e";`,
343
+ `import typia, { tags } from "typia";`,
344
+ "",
345
+ `import api from "@ORGANIZATION/PROJECT-api";`,
346
+ ...typeReferences.map(
347
+ (ref) =>
348
+ `import type { ${ref} } from "@ORGANIZATION/PROJECT-api/lib/structures/${ref}";`,
349
+ ),
350
+ "",
351
+ pointer.value.content,
352
+ ].join("\n");
353
+
354
+ pointer.value.content = pointer.value.content.replaceAll(
355
+ 'string & Format<"uuid">',
356
+ 'string & tags.Format<"uuid">',
357
+ );
358
+
320
359
  return pointer.value;
321
360
  }
322
361
 
362
+ function formatDiagnostic(
363
+ code: string,
364
+ lines: {
365
+ line: number; // line number
366
+ text: string;
367
+ start: number;
368
+ end: number; // exclusive
369
+ }[],
370
+ diagnostic: IAutoBeTypeScriptCompilerResult.IDiagnostic,
371
+ ): string {
372
+ const { start, length, messageText } = diagnostic;
373
+ const message = messageText;
374
+ if (typeof start === "number" && typeof length === "number") {
375
+ const end = start + length;
376
+ const problematicCode = code.substring(start, end);
377
+ const errorLine = lines.find((line) => line.end > start) ?? null;
378
+ const lineText = errorLine?.text ?? "";
379
+
380
+ const hints = getHints(message, lineText);
381
+
382
+ function createAdjustedArray(n: number): number[] {
383
+ let start = n - 2;
384
+
385
+ // 시작 값이 음수라면, 0부터 시작해서 5개의 숫자 생성
386
+ if (start < 0) {
387
+ start = 0;
388
+ }
389
+
390
+ return Array.from({ length: 5 }, (_, i) => start + i);
391
+ }
392
+
393
+ const errorLines = createAdjustedArray(errorLine?.line ?? 0);
394
+
395
+ const context = errorLines
396
+ .map((num) => {
397
+ if (num === errorLine?.line) {
398
+ if (lines[num - 1]) {
399
+ return `${lines[num - 1]?.text} // <- ERROR LINE (line:${num})`;
400
+ }
401
+ }
402
+ if (lines[num - 1]) {
403
+ return lines[num - 1]?.text;
404
+ }
405
+
406
+ return null;
407
+ })
408
+ .filter((el) => el !== null);
409
+
410
+ return [
411
+ "## Error Information",
412
+ `- Position: Characters ${start} to ${end}`,
413
+ `- Error Message: ${message}`,
414
+ `- Error Lines: \n${
415
+ context.length
416
+ ? [
417
+ "\t```ts", //
418
+ ...context.map((el) => `\t${el}`),
419
+ "\t```",
420
+ ].join("\n")
421
+ : "(none)"
422
+ }`,
423
+ `- Problematic Code: ${problematicCode.length > 0 ? `\`${problematicCode}\`` : "(none)"}`,
424
+ ...hints.map((hint) => `- Hint: ${hint}`),
425
+ ].join("\n");
426
+ }
427
+ return ["## Error Information", `- Error Message: ${message}`].join("\n");
428
+ }
429
+
430
+ function getHints(message: string, lineText: string): string[] {
431
+ const isTestValidator = lineText.includes("TestValidator");
432
+ const isTypia =
433
+ message === "Cannot find name 'Format'. Did you mean 'FormData'?";
434
+ const isJest = message === "Cannot find name 'expect'.";
435
+ const isCurrying =
436
+ isTestValidator && message === "Expected 1 arguments, but got 2";
437
+ const isAssignability =
438
+ /Argument of type '([^']+)' is not assignable to parameter of type '([^']+)'/.test(
439
+ message,
440
+ );
441
+
442
+ const hints: string[] = [];
443
+
444
+ if (isTypia) {
445
+ hints.push(
446
+ "If you want to use typia tags, use `tags.Format` instead of `Format`.",
447
+ );
448
+ }
449
+
450
+ if (isJest) {
451
+ hints.push(
452
+ 'Detected invalid `expect` usage. Use `TestValidator.equals("description")(expected)(actual)`.',
453
+ );
454
+ }
455
+
456
+ if (isCurrying) {
457
+ hints.push(
458
+ "`TestValidator.equals` is a curried function and must be called in **three steps**: `title → expected → actual`.",
459
+ );
460
+ } else if (isTestValidator) {
461
+ hints.push(
462
+ "The second argument `expected` must be assignable from the type of `actual`. Consider swapping the order if you get a type error.",
463
+ );
464
+ }
465
+
466
+ if (isAssignability && isTestValidator) {
467
+ const match = lineText
468
+ .trim()
469
+ .match(/TestValidator\.equals\("([^"]+)"\)\(([^)]+)\)\(([^)]+)\)/);
470
+ if (match) {
471
+ const [, title, expected, actual] = match;
472
+ if (actual.includes(expected)) {
473
+ hints.push(
474
+ `You can try rearranging the order like this: TestValidator.equals("${title}")(${actual})(${expected})`,
475
+ );
476
+ }
477
+ }
478
+ }
479
+
480
+ return hints;
481
+ }
482
+
323
483
  function createApplication<Model extends ILlmSchema.Model>(props: {
324
484
  model: Model;
325
485
  build: (next: ICorrectTestFunctionProps) => void;
@@ -3,8 +3,11 @@ import {
3
3
  IAgenticaHistoryJson,
4
4
  MicroAgentica,
5
5
  } from "@agentica/core";
6
- import { AutoBeOpenApi } from "@autobe/interface";
7
- import { AutoBeTestScenarioEvent } from "@autobe/interface";
6
+ import {
7
+ AutoBeOpenApi,
8
+ AutoBeTestScenario,
9
+ AutoBeTestScenarioEvent,
10
+ } from "@autobe/interface";
8
11
  import { ILlmApplication, ILlmSchema, IValidation } from "@samchon/openapi";
9
12
  import { IPointer } from "tstl";
10
13
  import typia from "typia";
@@ -31,7 +34,7 @@ export async function orchestrateTestScenario<Model extends ILlmSchema.Model>(
31
34
  let include: AutoBeOpenApi.IOperation[] = Array.from(operations);
32
35
 
33
36
  do {
34
- const matrix = divideArray({ array: include, capacity: 30 });
37
+ const matrix = divideArray({ array: include, capacity: 5 });
35
38
 
36
39
  await Promise.all(
37
40
  matrix.map(async (_include) => {
@@ -68,8 +71,8 @@ export async function orchestrateTestScenario<Model extends ILlmSchema.Model>(
68
71
  endpoint: pg.endpoint,
69
72
  draft: plan.draft,
70
73
  functionName: plan.functionName,
71
- dependencies: plan.dependsOn,
72
- } satisfies AutoBeTestScenarioEvent.IScenario;
74
+ dependencies: plan.dependencies,
75
+ } satisfies AutoBeTestScenario;
73
76
  });
74
77
  }),
75
78
  created_at: new Date().toISOString(),
@@ -120,7 +123,9 @@ const createHistoryProperties = (
120
123
  operations: AutoBeOpenApi.IOperation[],
121
124
  include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
122
125
  exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
123
- ) => [
126
+ ): Array<
127
+ IAgenticaHistoryJson.IAssistantMessage | IAgenticaHistoryJson.ISystemMessage
128
+ > => [
124
129
  {
125
130
  id: v4(),
126
131
  created_at: new Date().toISOString(),
@@ -132,17 +137,29 @@ const createHistoryProperties = (
132
137
  created_at: new Date().toISOString(),
133
138
  type: "systemMessage",
134
139
  text: [
140
+ "# Operations",
135
141
  "Below are the full operations. Please refer to this.",
136
142
  "Your role is to draft all test cases for each given Operation.",
137
143
  "It is also permissible to write multiple test codes on a single endpoint.",
138
144
  "However, rather than meaningless tests, business logic tests should be written and an E2E test situation should be assumed.",
139
145
  "",
146
+ "Please carefully analyze each operation to identify all dependencies required for testing.",
147
+ "For example, if you want to test liking and then deleting a post,",
148
+ "you might think to test post creation, liking, and unlike operations.",
149
+ "However, even if not explicitly mentioned, user registration and login are essential prerequisites.",
150
+ "Pay close attention to IDs and related values in the API,",
151
+ "and ensure you identify all dependencies between endpoints.",
152
+ "",
140
153
  "```json",
141
154
  JSON.stringify(
142
155
  operations.map((el) => ({
143
156
  path: el.path,
144
157
  method: el.method,
145
158
  summary: el.summary,
159
+ description: el.description,
160
+ parameters: el.parameters,
161
+ requestBody: el.requestBody,
162
+ responseBody: el.responseBody,
146
163
  })),
147
164
  ),
148
165
  "```",