Yuki Takei 9 месяцев назад
Родитель
Сommit
f874237180

+ 7 - 388
apps/app/src/features/openai/interfaces/editor-assistant/sse-schemas.spec.ts

@@ -2,7 +2,6 @@ import {
   SseMessageSchema,
   SseDetectedDiffSchema,
   SseFinalizedSchema,
-  hasApplicationResult,
   type SseMessage,
   type SseDetectedDiff,
   type SseFinalized,
@@ -192,343 +191,29 @@ describe('sse-schemas', () => {
   });
 
   describe('SseFinalizedSchema', () => {
-    test('should validate minimal finalized response', () => {
+    test('should validate finalized response with success true', () => {
       const validFinalized = {
-        finalized: {
-          message: 'Changes have been applied successfully.',
-          replacements: [],
-        },
+        success: true,
       };
 
       const result = SseFinalizedSchema.safeParse(validFinalized);
       expect(result.success).toBe(true);
       if (result.success) {
-        expect(result.data.finalized.message).toBe(validFinalized.finalized.message);
-        expect(result.data.finalized.replacements).toEqual([]);
-        expect(result.data.finalized.applicationResult).toBeUndefined();
+        expect(result.data.success).toBe(true);
       }
     });
 
-    test('should validate finalized response with replacements', () => {
+    test('should validate finalized response with success false', () => {
       const validFinalized = {
-        finalized: {
-          message: 'Successfully applied 2 changes.',
-          replacements: [
-            {
-              search: 'old code 1',
-              replace: 'new code 1',
-              startLine: 5,
-            },
-            {
-              search: 'old code 2',
-              replace: 'new code 2',
-              startLine: 10,
-              endLine: 12,
-            },
-          ],
-        },
+        success: false,
       };
 
       const result = SseFinalizedSchema.safeParse(validFinalized);
       expect(result.success).toBe(true);
       if (result.success) {
-        expect(result.data.finalized.replacements).toHaveLength(2);
-        expect(result.data.finalized.replacements[0].search).toBe('old code 1');
-        expect(result.data.finalized.replacements[1].endLine).toBe(12);
+        expect(result.data.success).toBe(false);
       }
     });
-
-    test('should validate finalized response with successful application result', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'All changes applied successfully.',
-          replacements: [
-            {
-              search: 'test code',
-              replace: 'updated code',
-              startLine: 1,
-            },
-          ],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-      if (result.success) {
-        expect(result.data.finalized.applicationResult?.success).toBe(true);
-        expect(result.data.finalized.applicationResult?.appliedCount).toBe(1);
-        expect(result.data.finalized.applicationResult?.totalCount).toBe(1);
-      }
-    });
-
-    test('should validate finalized response with failed application result', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'Some changes failed to apply.',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Could not find the specified search content',
-                line: 10,
-                details: {
-                  searchContent: 'missing code',
-                  bestMatch: 'similar code',
-                  similarity: 0.7,
-                  suggestions: ['Check line numbers', 'Verify content'],
-                  correctFormat: 'function example() {}',
-                  lineRange: '8-12',
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-      if (result.success) {
-        expect(result.data.finalized.applicationResult?.success).toBe(false);
-        expect(result.data.finalized.applicationResult?.failedParts).toHaveLength(1);
-        expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe('SEARCH_NOT_FOUND');
-        expect(result.data.finalized.applicationResult?.failedParts?.[0].details.similarity).toBe(0.7);
-      }
-    });
-
-    test('should validate all error types in failedParts', () => {
-      const errorTypes = [
-        'SEARCH_NOT_FOUND',
-        'SIMILARITY_TOO_LOW',
-        'MULTIPLE_MATCHES',
-        'EMPTY_SEARCH',
-        'MARKER_SEQUENCE_ERROR',
-        'CONTENT_ERROR',
-      ];
-
-      for (const errorType of errorTypes) {
-        const validFinalized = {
-          finalized: {
-            message: `Error type: ${errorType}`,
-            replacements: [],
-            applicationResult: {
-              success: false,
-              appliedCount: 0,
-              totalCount: 1,
-              failedParts: [
-                {
-                  type: errorType,
-                  message: `Test message for ${errorType}`,
-                  details: {
-                    searchContent: 'test',
-                    suggestions: [],
-                  },
-                },
-              ],
-            },
-          },
-        };
-
-        const result = SseFinalizedSchema.safeParse(validFinalized);
-        expect(result.success).toBe(true);
-        if (result.success) {
-          expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe(errorType);
-        }
-      }
-    });
-
-    test('should fail when finalized field is missing', () => {
-      const invalidFinalized = {};
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        expect(result.error.issues[0].code).toBe('invalid_type');
-        expect(result.error.issues[0].path).toEqual(['finalized']);
-      }
-    });
-
-    test('should fail when message is missing', () => {
-      const invalidFinalized = {
-        finalized: {
-          replacements: [],
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        const messageError = result.error.issues.find(issue => issue.path.includes('message'));
-        expect(messageError).toBeDefined();
-      }
-    });
-
-    test('should fail when replacements is missing', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test message',
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-      if (!result.success) {
-        const replacementsError = result.error.issues.find(issue => issue.path.includes('replacements'));
-        expect(replacementsError).toBeDefined();
-      }
-    });
-
-    test('should fail when appliedCount is negative', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: -1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when totalCount is negative', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: -1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when similarity is out of range', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SIMILARITY_TOO_LOW',
-                message: 'Low similarity',
-                details: {
-                  searchContent: 'test',
-                  similarity: 1.5, // Invalid: > 1.0
-                  suggestions: [],
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should fail when line number is not positive', () => {
-      const invalidFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Not found',
-                line: 0, // Invalid: must be positive
-                details: {
-                  searchContent: 'test',
-                  suggestions: [],
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(invalidFinalized);
-      expect(result.success).toBe(false);
-    });
-
-    test('should allow extra fields in finalized', () => {
-      const validFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-        },
-        extraField: 'ignored',
-      };
-
-      const result = SseFinalizedSchema.safeParse(validFinalized);
-      expect(result.success).toBe(true);
-    });
-  });
-
-  describe('hasApplicationResult helper', () => {
-    test('should return true when applicationResult is present', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(true);
-    });
-
-    test('should return false when applicationResult is undefined', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(false);
-    });
-
-    test('should return false when applicationResult is undefined (explicit)', () => {
-      const finalized: SseFinalized = {
-        finalized: {
-          message: 'Test',
-          replacements: [],
-          applicationResult: undefined,
-        },
-      };
-
-      expect(hasApplicationResult(finalized)).toBe(false);
-    });
   });
 
   describe('Type inference', () => {
@@ -556,77 +241,11 @@ describe('sse-schemas', () => {
 
     test('SseFinalized type should match schema', () => {
       const finalized: SseFinalized = {
-        finalized: {
-          message: 'Done',
-          replacements: [],
-        },
+        success: true,
       };
 
       const result = SseFinalizedSchema.safeParse(finalized);
       expect(result.success).toBe(true);
     });
   });
-
-  describe('Real-world scenarios', () => {
-    test('should validate complete SSE flow', () => {
-      const realWorldFinalized = {
-        finalized: {
-          message: 'Successfully refactored the authentication function and added error handling.',
-          replacements: [
-            {
-              search: 'function authenticate(token) {\n  return validateToken(token);\n}',
-              // eslint-disable-next-line max-len
-              replace: 'async function authenticate(token) {\n  try {\n    if (!token) {\n      throw new Error("Token is required");\n    }\n    return await validateToken(token);\n  } catch (error) {\n    console.error("Authentication failed:", error);\n    throw error;\n  }\n}',
-              startLine: 25,
-              endLine: 27,
-            },
-          ],
-          applicationResult: {
-            success: true,
-            appliedCount: 1,
-            totalCount: 1,
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(realWorldFinalized);
-      expect(result.success).toBe(true);
-    });
-
-    test('should validate error scenario with detailed feedback', () => {
-      const errorScenario = {
-        finalized: {
-          message: 'Failed to apply changes. The specified code was not found.',
-          replacements: [],
-          applicationResult: {
-            success: false,
-            appliedCount: 0,
-            totalCount: 1,
-            failedParts: [
-              {
-                type: 'SEARCH_NOT_FOUND',
-                message: 'Could not find exact match for the specified code',
-                line: 25,
-                details: {
-                  searchContent: 'function authenticate(token) {',
-                  bestMatch: 'function authenticateUser(userToken) {',
-                  similarity: 0.85,
-                  suggestions: [
-                    'Check if the function name has changed',
-                    'Verify the parameter name is correct',
-                    'Ensure the code structure matches exactly',
-                  ],
-                  correctFormat: 'function authenticateUser(userToken) {',
-                  lineRange: '20-30',
-                },
-              },
-            ],
-          },
-        },
-      };
-
-      const result = SseFinalizedSchema.safeParse(errorScenario);
-      expect(result.success).toBe(true);
-    });
-  });
 });

+ 2 - 37
apps/app/src/features/openai/interfaces/editor-assistant/sse-schemas.ts

@@ -15,47 +15,12 @@ export const SseDetectedDiffSchema = z.object({
   diff: LlmEditorAssistantDiffSchema,
 });
 
-// Enhanced finalized schema with detailed application results
+// Simplified finalized schema
 export const SseFinalizedSchema = z.object({
-  finalized: z.object({
-    message: z.string()
-      .describe('The final message that should be displayed in the chat window'),
-    replacements: z.array(LlmEditorAssistantDiffSchema),
-    // Enhanced error reporting from multi-search-replace processor
-    applicationResult: z.object({
-      success: z.boolean(),
-      appliedCount: z.number().int().min(0),
-      totalCount: z.number().int().min(0),
-      failedParts: z.array(z.object({
-        type: z.enum([
-          'SEARCH_NOT_FOUND',
-          'SIMILARITY_TOO_LOW',
-          'MULTIPLE_MATCHES',
-          'EMPTY_SEARCH',
-          'MARKER_SEQUENCE_ERROR',
-          'CONTENT_ERROR',
-        ]),
-        message: z.string(),
-        line: z.number().int().positive().optional(),
-        details: z.object({
-          searchContent: z.string(),
-          bestMatch: z.string().optional(),
-          similarity: z.number().min(0).max(1).optional(),
-          suggestions: z.array(z.string()),
-          correctFormat: z.string().optional(),
-          lineRange: z.string().optional(),
-        }),
-      })).optional(),
-    }).optional(),
-  }),
+  success: z.boolean(),
 });
 
 // Type definitions
 export type SseMessage = z.infer<typeof SseMessageSchema>;
 export type SseDetectedDiff = z.infer<typeof SseDetectedDiffSchema>;
 export type SseFinalized = z.infer<typeof SseFinalizedSchema>;
-
-// Helper functions for response type checking
-export const hasApplicationResult = (finalized: SseFinalized): boolean => {
-  return finalized.finalized.applicationResult !== undefined;
-};

+ 2 - 1
apps/app/src/features/openai/server/routes/edit/index.ts

@@ -205,8 +205,9 @@ export const postMessageToEditHandlersFactory: PostMessageHandlersFactory = (cro
         diffDetectedCallback: (detected) => {
           sseHelper.writeData<SseDetectedDiff>({ diff: detected });
         },
+        // eslint-disable-next-line @typescript-eslint/no-unused-vars
         dataFinalizedCallback: (message, replacements) => {
-          sseHelper.writeData<SseFinalized>({ finalized: { message: message ?? '', replacements } });
+          sseHelper.writeData<SseFinalized>({ success: true });
         },
       });