@@ -223,7 +223,7 @@ async def read_file_contents(
223
223
async def edit_file_contents (
224
224
self ,
225
225
file_path : str ,
226
- expected_hash : str ,
226
+ expected_file_hash : str ,
227
227
patches : List [Dict [str , Any ]],
228
228
encoding : str = "utf-8" ,
229
229
) -> Dict [str , Any ]:
@@ -252,7 +252,7 @@ async def edit_file_contents(
252
252
self ._validate_file_path (file_path )
253
253
try :
254
254
if not os .path .exists (file_path ):
255
- if expected_hash not in ["" , None ]: # Allow null hash
255
+ if expected_file_hash not in ["" , None ]: # Allow null hash
256
256
return self .create_error_response (
257
257
"File not found and non-empty hash provided" ,
258
258
suggestion = "append" ,
@@ -270,31 +270,31 @@ async def edit_file_contents(
270
270
hint = "Please check file permissions and try again" ,
271
271
)
272
272
# Initialize empty state for new file
273
- current_content = ""
274
- current_hash = ""
273
+ current_file_content = ""
274
+ current_file_hash = ""
275
275
lines : List [str ] = []
276
276
encoding = "utf-8"
277
277
else :
278
278
# Read current file content and verify hash
279
279
(
280
- current_content ,
280
+ current_file_content ,
281
281
_ ,
282
282
_ ,
283
- current_hash ,
283
+ current_file_hash ,
284
284
total_lines ,
285
285
_ ,
286
286
) = await self .read_file_contents (file_path , encoding = encoding )
287
287
288
288
# Treat empty file as new file
289
- if not current_content :
290
- current_content = ""
291
- current_hash = ""
289
+ if not current_file_content :
290
+ current_file_content = ""
291
+ current_file_hash = ""
292
292
lines = []
293
- elif current_content and expected_hash == "" :
293
+ elif current_file_content and expected_file_hash == "" :
294
294
return self .create_error_response (
295
295
"Unexpected error - Cannot treat existing file as new" ,
296
296
)
297
- elif current_hash != expected_hash :
297
+ elif current_file_hash != expected_file_hash :
298
298
suggestion = "patch"
299
299
hint = "Please use get_text_file_contents tool to get the current content and hash"
300
300
@@ -304,8 +304,8 @@ async def edit_file_contents(
304
304
hint = hint ,
305
305
)
306
306
else :
307
- lines = current_content .splitlines (keepends = True )
308
- lines = current_content .splitlines (keepends = True )
307
+ lines = current_file_content .splitlines (keepends = True )
308
+ lines = current_file_content .splitlines (keepends = True )
309
309
310
310
# Convert patches to EditPatch objects
311
311
patch_objects = [EditPatch .model_validate (p ) for p in patches ]
@@ -356,16 +356,26 @@ async def edit_file_contents(
356
356
"result" : "error" ,
357
357
"reason" : "End line must be greater than or equal to start line" ,
358
358
"file_hash" : None ,
359
- "content" : current_content ,
359
+ "content" : current_file_content ,
360
360
}
361
361
362
362
# Handle unexpected empty hash for existing file
363
363
if (
364
364
os .path .exists (file_path )
365
- and current_content
366
- and expected_hash == ""
365
+ and current_file_content
366
+ and expected_file_hash == ""
367
367
):
368
- return {"result" : "error" , "reason" : "Unexpected error" }
368
+ return {
369
+ "result" : "error" ,
370
+ "reason" : "File hash validation required: Empty hash provided for existing file" ,
371
+ "details" : {
372
+ "file_path" : file_path ,
373
+ "current_file_hash" : self .calculate_hash (
374
+ current_file_content
375
+ ),
376
+ "expected_file_hash" : expected_file_hash ,
377
+ },
378
+ }
369
379
370
380
# Calculate line ranges for zero-based indexing
371
381
start_zero = start - 1
@@ -379,7 +389,7 @@ async def edit_file_contents(
379
389
expected_range_hash = patch .range_hash
380
390
381
391
# Determine operation type and validate hash requirements
382
- if not os .path .exists (file_path ) or not current_content :
392
+ if not os .path .exists (file_path ) or not current_file_content :
383
393
# New file or empty file - treat as insertion
384
394
is_insertion = True
385
395
elif start_zero >= len (lines ):
@@ -418,15 +428,15 @@ async def edit_file_contents(
418
428
if not contents .strip ():
419
429
return {
420
430
"result" : "ok" ,
421
- "file_hash" : current_hash , # Return current hash since no changes made
431
+ "file_hash" : current_file_hash , # Return current hash since no changes made
422
432
"hint" : "For content deletion, please consider using delete_text_file_contents instead of patch with empty content" ,
423
433
"suggestion" : "delete" ,
424
434
}
425
435
426
436
# Set suggestions for alternative tools
427
437
suggestion_text : Optional [str ] = None
428
438
hint_text : Optional [str ] = None
429
- if not os .path .exists (file_path ) or not current_content :
439
+ if not os .path .exists (file_path ) or not current_file_content :
430
440
suggestion_text = "append"
431
441
hint_text = "For new or empty files, please consider using append_text_file_contents instead"
432
442
elif is_insertion :
0 commit comments