perf(kernel): hoist read-only check out of per-tool filter (#51)
runInference filtered the offered tool list with isReadOnlyMode(sessionId)
evaluated inside the per-tool .filter{} — a full log read+fold per offered
tool, per inference round (the audit's dominant O(events^2) hot path). The
flag is tool-independent, so read it once before the filter.
The per-tool-CALL re-check in dispatchToolCalls is left as-is: it is
semantically load-bearing (a read completing earlier in the same batch lifts
read-only mode for a later write), not redundant.
This commit is contained in:
+4
-1
@@ -2906,11 +2906,14 @@ abstract class SessionOrchestrator(
|
||||
tools = if (!withTools) {
|
||||
emptyList()
|
||||
} else {
|
||||
// Read the log ONCE for the read-only check instead of once per tool inside the filter
|
||||
// (the flag is tool-independent) — this filter runs per tool per inference round.
|
||||
val readOnlyMode = isReadOnlyMode(sessionId)
|
||||
stageConfig.effectiveAllowedTools
|
||||
.mapNotNull { effectives.registry?.resolve(it) }
|
||||
.filter { tool ->
|
||||
// ponytail: filter write tools while read-before-write block is active; restored once a read completes
|
||||
!isReadOnlyMode(sessionId) || ToolCapability.FILE_WRITE !in tool.requiredCapabilities
|
||||
!readOnlyMode || ToolCapability.FILE_WRITE !in tool.requiredCapabilities
|
||||
}
|
||||
.filter { tool ->
|
||||
// Read-loop break: keep only write tools (drop file_read/list_dir/shell) so
|
||||
|
||||
Reference in New Issue
Block a user