diff --git a/cmd/olliesrv/internal/agent/loop.go b/cmd/olliesrv/internal/agent/loop.go index 1b2fde0..70d52b8 100644 --- a/cmd/olliesrv/internal/agent/loop.go +++ b/cmd/olliesrv/internal/agent/loop.go @@ -417,22 +417,21 @@ func execToolCalls(rt *Runtime, ctx TurnCtx, toolCalls []backend.ToolCall, resul const conflictKeyGlobal = "\x00GLOBAL" // toolConflictKeys returns the set of resource keys a tool call touches. -// Scope "read" tools return nil (never conflict). Scope "global" tools -// return the global sentinel. Scope "write" (or empty) tools return their -// file path, or global if no path is detectable. +// Scope "read" tools return nil (never conflict). Scope "write" tools +// return their file path (or global if no path detectable). Everything +// else (scope "global" or unset) is a full serialization barrier. func toolConflictKeys(rt *Runtime, call backend.ToolCall) []string { scope := rt.ToolMeta[call.Name].Scope if scope == "read" { return nil // reads never conflict } - if scope == "global" { + if scope == "write" { + if p := extractFilePath(call.Arguments); p != "" { + return []string{p} + } return []string{conflictKeyGlobal} } - // "write" or unset: infer from path argument - if p := extractFilePath(call.Arguments); p != "" { - return []string{p} - } - // No detectable path: global barrier + // "global", empty, or anything else: full barrier return []string{conflictKeyGlobal} } diff --git a/data/tools/file_edit.meta b/data/tools/file_edit.meta index 5b8a7c0..ee1f180 100644 --- a/data/tools/file_edit.meta +++ b/data/tools/file_edit.meta @@ -2,7 +2,7 @@ "description": "Replace text in a file. Has fuzzy matching (whitespace/indent flexible).", "outputFormat": "diff", "resetsCounter": true, - "prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional)\n\n```\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\", replace_all=\"true\")\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations — add surrounding context to disambiguate, or use `replace_all=true`.", + "prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional)\n\n```\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\", replace_all=\"true\")\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations \u2014 add surrounding context to disambiguate, or use `replace_all=true`.", "args": { "type": "object", "required": [ @@ -28,5 +28,6 @@ "description": "Set to true/1/yes to replace all occurrences" } } - } + }, + "scope": "write" } diff --git a/data/tools/file_write.meta b/data/tools/file_write.meta index c525e4a..1696a2f 100644 --- a/data/tools/file_write.meta +++ b/data/tools/file_write.meta @@ -19,5 +19,6 @@ "description": "File content to write" } } - } + }, + "scope": "write" }