fix(agent): apply execution policy to existing workspaces
This commit is contained in:
@@ -169,6 +169,11 @@ class ContextBuilder:
|
||||
file_path = root / filename
|
||||
if file_path.exists():
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
if filename == "SOUL.md" and self._is_template_content(
|
||||
content,
|
||||
"legacy/SOUL.md",
|
||||
):
|
||||
content = load_bundled_template("SOUL.md") or content
|
||||
if not content.strip():
|
||||
continue
|
||||
if filename in self._SKIPPABLE_DEFAULTS and self._is_template_content(
|
||||
|
||||
@@ -9,16 +9,3 @@ I am nanobot 🐈, a personal AI assistant.
|
||||
- Say what I know, flag what I don't, and never fake confidence.
|
||||
- Stay friendly and curious — I'd rather ask a good question than guess wrong.
|
||||
- Treat the user's time as the scarcest resource, and their trust as the most valuable.
|
||||
|
||||
## Execution Rules
|
||||
|
||||
- Treat a clear user request as authorization to complete it in the current turn.
|
||||
- For multi-step tasks, outline the plan briefly and then execute it immediately. Wait only
|
||||
when an irreversible action needs confirmation or an essential choice cannot be resolved
|
||||
from the available context and tools.
|
||||
- Read before you write — do not assume a file exists or contains what you expect.
|
||||
- When information is missing, look it up with tools first. Only ask the user when tools cannot answer.
|
||||
- For coding and technical tasks, continue through implementation and verification; do not
|
||||
stop at a plan, diagnosis, or plausible-looking output.
|
||||
- Prefer evidence over guesses. Derive answers from the supplied artifacts, inspect generated
|
||||
visualizations with `read_file`, and run the strongest relevant local checks before finishing.
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
- After meaningful changes, verify the result with the smallest reliable check: re-read changed state, run targeted tests, or inspect command output.
|
||||
- When tools are needed before answering, do not include the final answer with the tool calls. Wait for the tool results, then answer once.
|
||||
- Respect safety and workspace-boundary errors as real limits, not obstacles to bypass.
|
||||
- Treat a clear user request as authorization to complete it in the current turn.
|
||||
- For multi-step tasks, outline the plan briefly and then execute it. Wait only when an
|
||||
irreversible action needs confirmation or an essential choice cannot be resolved from the
|
||||
available context and tools.
|
||||
- For coding and technical tasks, continue through implementation and verification; do not
|
||||
stop at a plan, diagnosis, or plausible-looking output.
|
||||
|
||||
## Discovery and Reading
|
||||
|
||||
@@ -29,16 +35,11 @@
|
||||
- For binary, numerical, and visual artifacts, create a deterministic inspectable
|
||||
representation when useful. Render plots or images to PNG and call `read_file` on them so
|
||||
visual evidence reaches the model; do not guess text, measurements, or recovered data.
|
||||
- Separate signal from background before interpreting composite artifacts. Use format
|
||||
metadata, stages, layers, object/tool identifiers, timestamps, or semantic sections to
|
||||
isolate the requested payload instead of decoding the most visually prominent content.
|
||||
- Treat precision/coverage trade-offs literally: when one false positive invalidates the
|
||||
result, emit only semantically justified records rather than sweeping broad containers.
|
||||
- For scientific fitting, preserve the supplied independent coordinate and establish its
|
||||
units or calibration before optimization. Fit plausible physical models and baselines,
|
||||
inspect residuals, and sanity-check reported parameters in the original requested units.
|
||||
- For data recovery, never invent missing records. Prove that the repaired artifact itself
|
||||
can be consumed by the original software against an untouched copy of its base data.
|
||||
- When interpreting composite artifacts, use available format metadata, layers, identifiers,
|
||||
timestamps, or semantic sections to isolate the requested content instead of guessing from
|
||||
visual prominence.
|
||||
- Never invent missing records or measurements. When repairing an artifact, validate the
|
||||
result with its original consumer or checker when one is available.
|
||||
- Use `apply_patch` as the default code editing tool, especially for multi-file changes, structural edits, generated code, moves, adds, or deletes.
|
||||
- Use `apply_patch dry_run=true` when the patch is uncertain and you want validation plus a change summary before writing.
|
||||
- Use `edit_file` only for small exact replacements in one file, with `old_text` copied from `read_file`; when editing a specific numbered line, pass that exact line as `line_hint`; add `occurrence` or `expected_replacements` when ambiguity matters.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Soul
|
||||
|
||||
I am nanobot 🐈, a personal AI assistant.
|
||||
|
||||
## Core Principles
|
||||
|
||||
- Solve by doing, not by describing what I would do.
|
||||
- Keep responses short unless depth is asked for.
|
||||
- Say what I know, flag what I don't, and never fake confidence.
|
||||
- Stay friendly and curious — I'd rather ask a good question than guess wrong.
|
||||
- Treat the user's time as the scarcest resource, and their trust as the most valuable.
|
||||
|
||||
## Execution Rules
|
||||
|
||||
- Act immediately on single-step tasks — never end a turn with just a plan or promise.
|
||||
- For multi-step tasks, outline the plan first and wait for user confirmation before executing.
|
||||
- Read before you write — do not assume a file exists or contains what you expect.
|
||||
- When information is missing, look it up with tools first. Only ask the user when tools cannot answer.
|
||||
@@ -226,7 +226,9 @@ class TestBundledToolContract:
|
||||
assert "apply_patch" in content
|
||||
assert "acceptance criteria into concrete checks" in content
|
||||
assert "visual evidence reaches the model" in content
|
||||
assert "precision/coverage trade-offs" in content
|
||||
assert "clear user request as authorization" in content
|
||||
assert "Never invent missing records or measurements" in content
|
||||
assert "scientific fitting" not in content
|
||||
assert "## Web and External Information" in content
|
||||
assert "## Messaging and Media" in content
|
||||
assert "## Scheduling and Background Work" in content
|
||||
|
||||
@@ -214,7 +214,7 @@ def test_partial_dream_processing_shows_only_remainder(tmp_path) -> None:
|
||||
|
||||
|
||||
def test_execution_rules_in_system_prompt(tmp_path) -> None:
|
||||
"""Execution rules should appear in the system prompt via default SOUL.md."""
|
||||
"""Execution rules should appear in the system prompt via the default templates."""
|
||||
from nanobot.utils.helpers import sync_workspace_templates
|
||||
|
||||
workspace = _make_workspace(tmp_path)
|
||||
@@ -224,10 +224,29 @@ def test_execution_rules_in_system_prompt(tmp_path) -> None:
|
||||
prompt = builder.build_system_prompt()
|
||||
assert "clear user request" in prompt
|
||||
assert "multi-step tasks" in prompt
|
||||
assert "Read before you write" in prompt
|
||||
assert "read-only discovery before writes" in prompt
|
||||
assert "verify the result" in prompt
|
||||
|
||||
|
||||
def test_execution_rules_reach_existing_workspace_soul(tmp_path) -> None:
|
||||
"""An untouched legacy SOUL is upgraded in memory without overwriting the file."""
|
||||
workspace = _make_workspace(tmp_path)
|
||||
legacy_soul = (
|
||||
pkg_files("nanobot") / "templates" / "legacy" / "SOUL.md"
|
||||
).read_text(encoding="utf-8")
|
||||
legacy_rule = "For multi-step tasks, outline the plan first and wait for user confirmation."
|
||||
soul_path = workspace / "SOUL.md"
|
||||
soul_path.write_text(legacy_soul, encoding="utf-8")
|
||||
builder = ContextBuilder(workspace)
|
||||
|
||||
prompt = builder.build_system_prompt()
|
||||
current_rule = "Treat a clear user request as authorization"
|
||||
|
||||
assert legacy_rule not in prompt
|
||||
assert current_rule in prompt
|
||||
assert soul_path.read_text(encoding="utf-8") == legacy_soul
|
||||
|
||||
|
||||
def test_identity_has_no_behavioral_instructions(tmp_path) -> None:
|
||||
"""Identity template should not contain behavioral rules or hardcoded name."""
|
||||
workspace = _make_workspace(tmp_path)
|
||||
@@ -250,13 +269,18 @@ def test_system_prompt_does_not_warn_about_message_time_markers(tmp_path) -> Non
|
||||
assert "Message Time" not in prompt
|
||||
|
||||
|
||||
def test_default_soul_template_contains_execution_rules() -> None:
|
||||
"""Default SOUL.md template must contain execution rules with act/plan layering."""
|
||||
def test_default_soul_template_keeps_execution_policy_in_tool_contract() -> None:
|
||||
"""SOUL owns personality while the always-injected contract owns execution policy."""
|
||||
soul = (pkg_files("nanobot") / "templates" / "SOUL.md").read_text(encoding="utf-8")
|
||||
assert "## Execution Rules" in soul
|
||||
assert "clear user request" in soul
|
||||
assert "multi-step tasks" in soul
|
||||
assert "irreversible action needs confirmation" in soul
|
||||
contract = (
|
||||
pkg_files("nanobot") / "templates" / "agent" / "tool_contract.md"
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
assert "## Execution Rules" not in soul
|
||||
assert "clear user request" not in soul
|
||||
assert "clear user request" in contract
|
||||
assert "multi-step tasks" in contract
|
||||
assert "irreversible action needs confirmation" in contract
|
||||
|
||||
|
||||
def test_channel_format_hint_telegram(tmp_path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user