fix(infra): single-read file_read (no double disk I/O for hash) + bail health poll on dead process
This commit is contained in:
+3
-1
@@ -151,10 +151,12 @@ class DefaultModelManager(
|
|||||||
currentDescriptor = null
|
currentDescriptor = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnusedParameter")
|
|
||||||
private suspend fun waitForHealthy(process: LlamaProcess): Boolean {
|
private suspend fun waitForHealthy(process: LlamaProcess): Boolean {
|
||||||
val endTime = Clock.System.now().toEpochMilliseconds() + healthTimeoutMs
|
val endTime = Clock.System.now().toEpochMilliseconds() + healthTimeoutMs
|
||||||
while (Clock.System.now().toEpochMilliseconds() < endTime) {
|
while (Clock.System.now().toEpochMilliseconds() < endTime) {
|
||||||
|
// A crashed process (bad --model, port clash) never gets healthy; polling the full
|
||||||
|
// timeout is pure dead time. Bail as soon as it's gone.
|
||||||
|
if (!process.isAlive) return false
|
||||||
try {
|
try {
|
||||||
val response = httpClient.get("http://$host:$port/health").body<String>()
|
val response = httpClient.get("http://$host:$port/health").body<String>()
|
||||||
if (response.contains("\"status\":\"healthy\"") || response.contains("ok")) {
|
if (response.contains("\"status\":\"healthy\"") || response.contains("ok")) {
|
||||||
|
|||||||
+7
-4
@@ -141,7 +141,10 @@ class FileReadTool(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun readFile(path: Path, startLine: Int?, endLine: Int?, request: ToolRequest): ToolResult = runCatching {
|
private fun readFile(path: Path, startLine: Int?, endLine: Int?, request: ToolRequest): ToolResult = runCatching {
|
||||||
val lines = Files.readAllLines(path)
|
// Read the file once. Lines and the (whole-read) content hash both derive from these bytes,
|
||||||
|
// so a full read no longer hits the disk twice (readAllLines + readAllBytes for the hash).
|
||||||
|
val bytes = Files.readAllBytes(path)
|
||||||
|
val lines = bytes.inputStream().bufferedReader().readLines()
|
||||||
val start = ((startLine ?: 1) - 1).coerceAtLeast(0)
|
val start = ((startLine ?: 1) - 1).coerceAtLeast(0)
|
||||||
val end = (endLine ?: lines.size).coerceAtMost(lines.size)
|
val end = (endLine ?: lines.size).coerceAtMost(lines.size)
|
||||||
val selected = lines.subList(start, end)
|
val selected = lines.subList(start, end)
|
||||||
@@ -166,7 +169,7 @@ class FileReadTool(
|
|||||||
// against what the agent actually saw. A partial or truncated view establishes no baseline —
|
// against what the agent actually saw. A partial or truncated view establishes no baseline —
|
||||||
// the agent must read the relevant range before editing.
|
// the agent must read the relevant range before editing.
|
||||||
val sawWholeFile = startLine == null && endLine == null && !lineCapped && !charCapped
|
val sawWholeFile = startLine == null && endLine == null && !lineCapped && !charCapped
|
||||||
val metadata = if (sawWholeFile) mapOf("contentHash" to sha256(path)) else emptyMap()
|
val metadata = if (sawWholeFile) mapOf("contentHash" to sha256(bytes)) else emptyMap()
|
||||||
ToolResult.Success(
|
ToolResult.Success(
|
||||||
invocationId = request.invocationId,
|
invocationId = request.invocationId,
|
||||||
output = content + note,
|
output = content + note,
|
||||||
@@ -180,8 +183,8 @@ class FileReadTool(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sha256(path: Path): String =
|
private fun sha256(bytes: ByteArray): String =
|
||||||
java.security.MessageDigest.getInstance("SHA-256").digest(Files.readAllBytes(path))
|
java.security.MessageDigest.getInstance("SHA-256").digest(bytes)
|
||||||
.joinToString("") { "%02x".format(it) }
|
.joinToString("") { "%02x".format(it) }
|
||||||
|
|
||||||
private fun listDir(path: Path, request: ToolRequest): ToolResult = runCatching {
|
private fun listDir(path: Path, request: ToolRequest): ToolResult = runCatching {
|
||||||
|
|||||||
Reference in New Issue
Block a user