fix(list_dir): file-vs-dir mismatch gives an actionable hint (#45)
The 'Not a directory' branch returned a bare message; models re-issued the identical list_dir until cancel (session a60c54b0). Name the remedy: the path is a FILE — file_read it or delete/convert it first. Regression test added.
This commit is contained in:
+9
-1
@@ -111,7 +111,15 @@ class ListDirTool(
|
||||
ToolResult.Failure(request.invocationId, msg, recoverable = true)
|
||||
}
|
||||
!Files.isDirectory(root) ->
|
||||
ToolResult.Failure(request.invocationId, "Not a directory: $pathString", recoverable = true)
|
||||
// Explicit file-vs-dir mismatch: a bare "Not a directory" left models re-issuing the
|
||||
// identical list_dir until cancel (session a60c54b0). Name the remedy so the next
|
||||
// action is unambiguous — file_read it, or delete/convert it first.
|
||||
ToolResult.Failure(
|
||||
request.invocationId,
|
||||
"Not a directory: $pathString is a FILE, not a directory. " +
|
||||
"Use file_read to read it, or delete/convert it before listing it as a directory.",
|
||||
recoverable = true,
|
||||
)
|
||||
else -> runCatching { walk(root, recursive, request) }.getOrElse {
|
||||
ToolResult.Failure(request.invocationId, "Failed to list dir: ${it.message}", recoverable = false)
|
||||
}
|
||||
|
||||
+13
@@ -58,6 +58,19 @@ class ListDirToolTest {
|
||||
assertFalse(out.contains("deep"), out)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `listing a file gives a recoverable file-vs-dir hint, not a bare error`(): Unit = runBlocking {
|
||||
// Regression (session a60c54b0): list_dir on a plain file returned a bare "Not a directory"
|
||||
// and models re-issued the identical call until cancel. The failure must name the remedy.
|
||||
val root = Files.createTempDirectory("listdir")
|
||||
Files.writeString(root.resolve("pages"), "i am a file")
|
||||
val tool = ListDirTool(allowedPaths = setOf(root), workingDir = root)
|
||||
val result = tool.execute(request(path = "pages")) as ToolResult.Failure
|
||||
assertTrue(result.recoverable, "file-vs-dir mismatch is recoverable")
|
||||
assertTrue(result.reason.contains("FILE"), result.reason)
|
||||
assertTrue(result.reason.contains("file_read"), result.reason)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `non-recursive lists only immediate children`(): Unit = runBlocking {
|
||||
val root = Files.createTempDirectory("listdir")
|
||||
|
||||
Reference in New Issue
Block a user