fix(inference,tools): unblock llama.cpp tool stages + workspace-relative file_read
Two fixes surfaced by the 2026-06-08 QA audit running role_pipeline on a local
llama-server.
F-001: LlamaCppInferenceProvider sent both a GBNF grammar and tools on the same
request; llama.cpp rejects the combination ("Cannot use custom grammar
constraints with tools"), failing every stage that has tools and produces a
schema-constrained artifact. Drop the grammar when tools are present and rely on
post-hoc schema validation + retry (invariant #7 still holds). TODO left for a
first-class emit_artifact tool as the proper fix.
F-005: FileReadTool resolved relative paths via toAbsolutePath() against the JVM
process cwd instead of the bound workspace, so the file-read jail anchored to the
wrong root and disagreed with the Plane-2 PATH_CONTAINMENT check. Add workingDir
to FileReadConfig, wire workspace.workingDir in the per-workspace tool builder,
and give FileReadTool a resolvePath() mirroring FileWriteTool/FileEditTool.
This commit is contained in:
+13
-2
@@ -86,8 +86,19 @@ class LlamaCppInferenceProvider(
|
||||
)
|
||||
}
|
||||
|
||||
val tools = request.tools.takeIf { it.isNotEmpty() }
|
||||
|
||||
// llama.cpp rejects requests that carry BOTH a custom grammar and tools
|
||||
// ("Cannot use custom grammar constraints with tools"). When a stage has tools,
|
||||
// we drop the grammar and rely on post-hoc schema validation + retry to keep the
|
||||
// artifact constrained (invariant #7: LLM output is untrusted until validated).
|
||||
// TODO: replace this implicit "free-form JSON, validate after" path with a
|
||||
// first-class artifact-emission tool — the LLM calls e.g. emit_artifact(path,
|
||||
// content, description) the same way it calls file_read/file_write, so artifact
|
||||
// production is an explicit, schema-checked tool call rather than a grammar
|
||||
// constraint that can't coexist with other tools.
|
||||
val grammar = when (val fmt = request.responseFormat) {
|
||||
is ResponseFormat.Json -> GbnfGrammarConverter.convert(fmt.schema)
|
||||
is ResponseFormat.Json -> if (tools == null) GbnfGrammarConverter.convert(fmt.schema) else null
|
||||
ResponseFormat.Text -> null
|
||||
}
|
||||
|
||||
@@ -101,7 +112,7 @@ class LlamaCppInferenceProvider(
|
||||
seed = request.generationConfig.seed,
|
||||
stream = false,
|
||||
grammar = grammar,
|
||||
tools = request.tools.takeIf { it.isNotEmpty() },
|
||||
tools = tools,
|
||||
)
|
||||
|
||||
val encoded = json.encodeToString(body)
|
||||
|
||||
Reference in New Issue
Block a user