Initial Commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""The one question vm_agent stops to ask, and how it decides to ask it.
|
||||
|
||||
WHY THIS IS A SEPARATE MODULE
|
||||
|
||||
Two reasons, and the second is the real one.
|
||||
|
||||
It is dependency-free, so it can be unit-tested on the host without the
|
||||
container - the same arrangement as matlab_lint.py, and for the same
|
||||
reason: the interesting half of this rule cannot be tested over HTTP. A
|
||||
task that is let through starts a real VM session, which is minutes long
|
||||
by design, and the smoke suite's per-case timeout is 90 seconds.
|
||||
|
||||
And it puts the rule somewhere findable. It is the only pre-flight
|
||||
refusal in the suite that is about the CALLER's judgement rather than
|
||||
about a malformed argument, so it will be argued with, and the argument
|
||||
should happen against a file that explains itself.
|
||||
|
||||
WHY THE RULE EXISTS
|
||||
|
||||
A Python script runs on both machines. A `.sh` runs only on Ubuntu; a
|
||||
`.ps1` or `.bat` only on Windows. The model has to choose, and it has no
|
||||
way to know unless the user said - but the machine is destroyed at the
|
||||
end of the session, so guessing wrong does not cost a retry, it costs the
|
||||
whole session.
|
||||
|
||||
The system prompt asks the model to check first. That is not enough on
|
||||
its own: this file's oldest and most-repeated finding is that the model
|
||||
treats tool output as fact and system-prompt text as advice, and a prompt
|
||||
rule loses to an explicit user demand. So the tool refuses, in its own
|
||||
output, and hands back the exact question to relay.
|
||||
|
||||
WHY IT HAS TO BE NARROW
|
||||
|
||||
Firing when the caller has already said which machine would be worse than
|
||||
not firing at all. It would teach the model that the way past this tool
|
||||
is to add a magic word, rather than to ask - and a model that has learned
|
||||
to appease a check has stopped reading it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
# Things that run on both machines. Word-bounded throughout: `\bgo\b`
|
||||
# rather than `go`, or every mention of "gopher" and "going" trips it.
|
||||
CROSS_PLATFORM = re.compile(
|
||||
r"\bpython3?\b|\bpy\b|\.py\b|\bpip3?\b|\bnode\b|\bnpm\b|\.js\b"
|
||||
r"|\bjava\b|\bgo\b|\bgolang\b|\brust\b|\bcargo\b|\bdotnet\b|\bruby\b|\bperl\b",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
# Deliberately generous. The point is to catch a silent guess, not to
|
||||
# interrogate a caller who has already been clear - so a mention of the
|
||||
# shell, the file extension or the package manager counts as having said.
|
||||
_SAYS_UBUNTU = (
|
||||
"ubuntu", "linux", "debian", "bash", "sh script", ".sh", "shell script",
|
||||
"apt ", "apt-get", "apt install", "/usr/", "/etc/", "/home/", "systemd",
|
||||
)
|
||||
_SAYS_WINDOWS = (
|
||||
"windows", "powershell", "pwsh", ".ps1", "batch", ".bat", ".cmd",
|
||||
"cmd.exe", "winget", "c:\\", "registry", ".exe",
|
||||
)
|
||||
|
||||
|
||||
def names_its_machine(task: str, os_name: str) -> bool:
|
||||
"""Has the caller already said which machine, in the task itself?"""
|
||||
lowered = (task or "").lower()
|
||||
words = _SAYS_WINDOWS if os_name == "windows" else _SAYS_UBUNTU
|
||||
return any(word in lowered for word in words)
|
||||
|
||||
|
||||
def should_ask(task: str, os_name: str) -> bool:
|
||||
"""True when the tool should stop and have the user asked."""
|
||||
return bool(CROSS_PLATFORM.search(task or "")) and not names_its_machine(task, os_name)
|
||||
|
||||
|
||||
def question(os_name: str) -> str:
|
||||
"""The refusal, written for the model to relay rather than to obey."""
|
||||
other = "Windows" if os_name == "ubuntu" else "Ubuntu"
|
||||
return (
|
||||
f"CANNOT DO THAT YET: this task mentions something that runs on both machines, "
|
||||
f"and you chose {os_name}. Ask the user which they want - {other} is just as "
|
||||
"likely and there is nothing in the task text to tell you.\n\n"
|
||||
"Put it to them in one round, then call again with their answer. If they do not "
|
||||
f"mind, say which you picked and call again with the task naming {os_name} "
|
||||
"explicitly. Guessing costs the whole session: the machine is destroyed at the "
|
||||
"end of it, so there is nothing to correct afterwards."
|
||||
)
|
||||
Reference in New Issue
Block a user