Skip to content

feature: diff feedback #52

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
darinkishore opened this issue Apr 8, 2025 · 1 comment
Open

feature: diff feedback #52

darinkishore opened this issue Apr 8, 2025 · 1 comment

Comments

@darinkishore
Copy link

was using augment and i think their diff feedback was pretty cool. maybe smth like this would be useful for wcgw too?

Failed to edit the file src/canvas_mcp/sync_service.py. See below for details.
Result for str_replace_entries[0]:
No replacement was performed, oldStr did not appear verbatim in src/canvas_mcp/sync_service.py.
The content in the specified region is:
    93	            for course in courses
    94	            if getattr(course, "enrollment_term_id", None) == max_term_id
    95	        ]
    96	
    97	    def sync_courses(
    98	        self, user_id: Optional[str] = None, term_id: Optional[int] = -1
    99	    ) -> List[int]:
   100	        """
   101	        Synchronize course data from Canvas to the local database.
   102	
   103	        Args:
   104	            user_id: Optional user ID to filter courses
   105	            term_id: Optional term ID to filter courses
   106	                     (default is -1, which selects only the most recent term)
   107	
   108	        Returns:
   109	            List of local course IDs that were synced
   110	        """
   111	        if not self.api_adapter.is_available():
   112	            logger.error("Canvas API adapter is not available")
   113	            return []
   114	
   115	        # Fetch Stage
   116	        user = self.api_adapter.get_current_user_raw()
   117	        if not user:
   118	            logger.error("Failed to get current user from Canvas API")
   119	            return []
   120	
   121	        # Use the provided user_id or get it from the current user
   122	        if user_id is None:
   123	            user_id = str(user.id)
   124	
   125	        # Get courses from Canvas
   126	        raw_courses = self.api_adapter.get_courses_raw(user)
   127	        if not raw_courses:
   128	            logger.warning("No courses found in Canvas API")
   129	            return []
   130	
   131	        # Filter Stage
   132	        filtered_courses = self._filter_courses_by_term(raw_courses, term_id)
   133	        if not filtered_courses:
   134	            logger.warning("No courses found after term filtering")
   135	            return []
   136	
   137	        # Prepare/Validate Stage
   138	        valid_courses = []
   139	        for raw_course in filtered_courses:
   140	            try:
   141	                # Get detailed course info if needed
   142	                detailed_course = self.api_adapter.get_course_raw(raw_course.id)
   143	
   144	                # Combine data for validation
   145	                course_data = {
   146	                    "id": raw_course.id,
   147	                    "course_code": getattr(raw_course, "course_code", ""),
   148	                    "name": getattr(raw_course, "name", ""),
   149	                    "instructor": getattr(detailed_course, "teacher_name", None)
   150	                    if detailed_course
   151	                    else None,
   152	                    "description": getattr(detailed_course, "description", None)
   153	                    if detailed_course
   154	                    else None,
   155	                    "start_at": getattr(raw_course, "start_at", None),
   156	                    "end_at": getattr(raw_course, "end_at", None),
   157	                }
   158	
   159	                # Validate using Pydantic model
   160	                db_course = DBCourse.model_validate(course_data)
   161	
   162	                # Get syllabus body if available
   163	                syllabus_body = (
   164	                    getattr(detailed_course, "syllabus_body", None)
   165	                    if detailed_course
   166	                    else None
   167	                )
   168	
   169	                valid_courses.append((db_course, syllabus_body))
   170	            except Exception as e:
   171	                logger.error(
   172	                    f"Error validating course {getattr(raw_course, 'id', 'unknown')}: {e}"
   173	                )
   174	
   175	        if not valid_courses:
   176	            logger.warning("No valid courses found after validation")
   177	            return []
   178	
   179	        # Persist Courses Stage
   180	        conn, db = self._get_db()
   181	        local_ids = []
   182	        canvas_to_local_id = {}
   183	
   184	        try:
   185	            with conn:  # Transaction
   186	                for db_course, _ in valid_courses:
   187	                    try:
   188	                        # Convert Pydantic model to dict for sqlite-utils
   189	                        course_dict = db_course.model_dump(
   190	                            exclude={"created_at", "updated_at"}
   191	                        )
   192	                        course_dict["updated_at"] = datetime.now().isoformat()
   193	
   194	                        # Upsert the course
   195	                        db["courses"].upsert(
   196	                            course_dict, pk="canvas_course_id", alter=True
   197	                        )
   198	
   199	                        # Get the local ID
   200	                        local_course = db["courses"].get(
   201	                            db_course.canvas_course_id, pk="canvas_course_id"
   202	                        )
   203	                        if local_course:
   204	                            local_id = local_course["id"]
   205	                            local_ids.append(local_id)
   206	                            canvas_to_local_id[db_course.canvas_course_id] = local_id
   207	                    except Exception as e:
   208	                        logger.error(
   209	                            f"Error persisting course {db_course.canvas_course_id}: {e}"
   210	                        )
   211	        finally:
   212	            self._close_db(conn)
   213	
   214	        # Persist Syllabi Stage
   215	        conn, db = self._get_db()
   216	
   217	        try:
   218	            with conn:  # Transaction
   219	                for db_course, syllabus_body in valid_courses:
   220	                    try:
   221	                        local_id = canvas_to_local_id.get(db_course.canvas_course_id)
   222	                        if not local_id:
   223	                            continue
   224	
   225	                        # Prepare syllabus data
   226	                        content_type = detect_content_type(syllabus_body)
   227	
   228	                        syllabus_dict = {
   229	                            "course_id": local_id,
   230	                            "content": syllabus_body,
   231	                            "content_type": content_type,
   232	                            "is_parsed": False,
   233	                            "updated_at": datetime.now().isoformat(),
   234	                        }
   235	
   236	                        # Upsert the syllabus
   237	                        db["syllabi"].upsert(
   238	                            syllabus_dict,
   239	                            pk="course_id",
   240	                            foreign_keys=[("course_id", "courses", "id")],
   241	                            alter=True,
   242	                        )

Diff between oldStr and the specified region is:
===================================================================
--- oldStr
+++ regionContent
@@ -1,4 +1,6 @@
-    def sync_courses(self, user_id: Optional[str] = None, term_id: Optional[int] = -1) -> List[int]:
+    def sync_courses(
+        self, user_id: Optional[str] = None, term_id: Optional[int] = -1
+    ) -> List[int]:
         """
         Synchronize course data from Canvas to the local database.
 
@@ -48,8 +50,12 @@
                     "id": raw_course.id,
                     "course_code": getattr(raw_course, "course_code", ""),
                     "name": getattr(raw_course, "name", ""),
-                    "instructor": getattr(detailed_course, "teacher_name", None) if detailed_course else None,
-                    "description": getattr(detailed_course, "description", None) if detailed_course else None,
+                    "instructor": getattr(detailed_course, "teacher_name", None)
+                    if detailed_course
+                    else None,
+                    "description": getattr(detailed_course, "description", None)
+                    if detailed_course
+                    else None,
                     "start_at": getattr(raw_course, "start_at", None),
                     "end_at": getattr(raw_course, "end_at", None),
                 }
@@ -58,11 +64,17 @@
                 db_course = DBCourse.model_validate(course_data)
 
                 # Get syllabus body if available
-                syllabus_body = getattr(detailed_course, "syllabus_body", None) if detailed_course else None
+                syllabus_body = (
+                    getattr(detailed_course, "syllabus_body", None)
+                    if detailed_course
+                    else None
+                )
 
                 valid_courses.append((db_course, syllabus_body))
             except Exception as e:
-                logger.error(f"Error validating course {getattr(raw_course, 'id', 'unknown')}: {e}")
+                logger.error(
+                    f"Error validating course {getattr(raw_course, 'id', 'unknown')}: {e}"
+                )
 
         if not valid_courses:
             logger.warning("No valid courses found after validation")
@@ -78,24 +90,28 @@
                 for db_course, _ in valid_courses:
                     try:
                         # Convert Pydantic model to dict for sqlite-utils
-                        course_dict = db_course.model_dump(exclude={"created_at", "updated_at"})
+                        course_dict = db_course.model_dump(
+                            exclude={"created_at", "updated_at"}
+                        )
                         course_dict["updated_at"] = datetime.now().isoformat()
 
                         # Upsert the course
                         db["courses"].upsert(
-                            course_dict,
-                            pk="canvas_course_id",
-                            alter=True
+                            course_dict, pk="canvas_course_id", alter=True
                         )
 
                         # Get the local ID
-                        local_course = db["courses"].get(db_course.canvas_course_id, pk="canvas_course_id")
+                        local_course = db["courses"].get(
+                            db_course.canvas_course_id, pk="canvas_course_id"
+                        )
                         if local_course:
                             local_id = local_course["id"]
                             local_ids.append(local_id)
                             canvas_to_local_id[db_course.canvas_course_id] = local_id
                     except Exception as e:
-                        logger.error(f"Error persisting course {db_course.canvas_course_id}: {e}")
+                        logger.error(
+                            f"Error persisting course {db_course.canvas_course_id}: {e}"
+                        )
         finally:
             self._close_db(conn)
 
@@ -118,19 +134,9 @@
                             "content": syllabus_body,
                             "content_type": content_type,
                             "is_parsed": False,
-                            "updated_at": datetime.now().isoformat()
+                            "updated_at": datetime.now().isoformat(),
                         }
 
                         # Upsert the syllabus
                         db["syllabi"].upsert(
                             syllabus_dict,
-                            pk="course_id",
-                            foreign_keys=[("course_id", "courses", "id")],
-                            alter=True
-                        )
-                    except Exception as e:
-                        logger.error(f"Error persisting syllabus for course {db_course.canvas_course_id}: {e}")
-        finally:
-            self._close_db(conn)
-
-        return local_ids


Fix failed str_replace_entries accordingly and try again.

@rusiaaman
Copy link
Owner

This is cool.

However, it's not immediately obvious why giving same information twice helps here. The model knows the old string, and if we give the closest matching region (which the file edit tool does), then it can derive the diff itself (which it should be good at).

Do you have some comparison between the two approaches with respect to model's followup accuracy?

In any case I'll try it out sometime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants