mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +00:00
feat(agent): add configurable coding_instructions
agent.coding_instructions (a string or list) is appended to the coding brief as its own stable system block, so users can pin project-wide workflow rules without editing the shipped brief. Coding-posture only and cache-safe (resolved once per session; takes effect next session). Empty by default.
This commit is contained in:
parent
a10113658b
commit
821d9f709f
4 changed files with 79 additions and 0 deletions
|
|
@ -353,6 +353,29 @@ def _coding_mode(config: Optional[dict[str, Any]]) -> str:
|
|||
return "auto"
|
||||
|
||||
|
||||
def _coding_instructions(config: Optional[dict[str, Any]]) -> str:
|
||||
"""Standing operator instructions for the coding posture (config).
|
||||
|
||||
``agent.coding_instructions`` — a string or list of strings appended to the
|
||||
coding brief as an extra stable system block, so a user can pin project-wide
|
||||
coding-workflow rules (e.g. "for UI work don't run tsc/lint until I approve;
|
||||
clean the diff before committing") without editing the shipped brief.
|
||||
Cache-safe: resolved once per session into the stable system-prompt tier,
|
||||
like the rest of the posture.
|
||||
"""
|
||||
if config is None:
|
||||
try:
|
||||
from hermes_cli.config import load_config
|
||||
|
||||
config = load_config()
|
||||
except Exception:
|
||||
config = {}
|
||||
raw = ((config or {}).get("agent", {}) or {}).get("coding_instructions", "")
|
||||
if isinstance(raw, (list, tuple)):
|
||||
return "\n".join(str(item).strip() for item in raw if str(item).strip())
|
||||
return str(raw or "").strip()
|
||||
|
||||
|
||||
def _resolve_cwd(cwd: Optional[str | Path]) -> Path:
|
||||
if cwd:
|
||||
return Path(cwd).expanduser()
|
||||
|
|
@ -459,6 +482,9 @@ class RuntimeMode:
|
|||
# only to steer edit-format guidance toward the model's family — see
|
||||
# ``_edit_format_line``. Fixed for the session, so cache-safe.
|
||||
model: Optional[str] = None
|
||||
# Standing operator instructions (``agent.coding_instructions``), appended
|
||||
# as an extra stable system block. Empty unless the user configures it.
|
||||
instructions: str = ""
|
||||
|
||||
@property
|
||||
def kind(self) -> str:
|
||||
|
|
@ -505,6 +531,10 @@ class RuntimeMode:
|
|||
workspace = build_coding_workspace_block(self.cwd)
|
||||
if workspace:
|
||||
blocks.append(workspace)
|
||||
# Operator instructions ride their own block so the brief (block 0) stays
|
||||
# byte-stable and cache-keyed independently of user config.
|
||||
if self.instructions:
|
||||
blocks.append(f"Operator instructions (from config):\n{self.instructions}")
|
||||
return blocks
|
||||
|
||||
def compact_skill_categories(self) -> frozenset[str]:
|
||||
|
|
@ -557,6 +587,7 @@ def resolve_runtime_mode(
|
|||
cwd=resolved_cwd,
|
||||
config_mode=mode,
|
||||
model=model,
|
||||
instructions=_coding_instructions(config),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -646,6 +646,14 @@ agent:
|
|||
# force it on or off; the HERMES_VERIFY_ON_STOP env var (1/0) takes precedence.
|
||||
# verify_on_stop: auto
|
||||
|
||||
# Standing operator instructions for the coding posture (when Hermes is in a
|
||||
# code workspace). Appended to the coding brief as an extra system block, so
|
||||
# you can pin project-wide workflow rules without editing the shipped brief.
|
||||
# Accepts a string or a list of strings. Takes effect next session.
|
||||
# coding_instructions:
|
||||
# - "For UI work, don't run tsc/lint until I approve the look."
|
||||
# - "Clean the diff before you commit and push."
|
||||
|
||||
# When verify-on-stop finds edited code without fresh verification evidence,
|
||||
# append guidance for creative UI work (avoid broad tsc/lint/test before visual
|
||||
# approval) and clean-diff expectations. Set false to keep that nudge terse.
|
||||
|
|
|
|||
|
|
@ -999,6 +999,13 @@ DEFAULT_CONFIG = {
|
|||
# "on" — force the prompt posture everywhere.
|
||||
# "off" — disable entirely.
|
||||
"coding_context": "auto",
|
||||
# Standing operator instructions for the coding posture. A string (or
|
||||
# list of strings) appended to the coding brief as an extra stable
|
||||
# system block — pin project-wide workflow rules here instead of editing
|
||||
# the shipped brief, e.g. "For UI work, don't run tsc/lint until I
|
||||
# approve. Clean the diff before you commit and push." Cache-safe:
|
||||
# takes effect next session. Empty by default.
|
||||
"coding_instructions": "",
|
||||
# When verify-on-stop finds edited code without fresh verification
|
||||
# evidence, append guidance for creative UI work (avoid broad
|
||||
# tsc/lint/test before visual approval) and clean-diff expectations.
|
||||
|
|
|
|||
|
|
@ -353,6 +353,39 @@ class TestRuntimeMode:
|
|||
assert any("coding agent" in b for b in blocks)
|
||||
assert any("Workspace" in b for b in blocks)
|
||||
|
||||
def test_coding_instructions_append_their_own_block(self, tmp_path):
|
||||
_git_init(tmp_path)
|
||||
cfg = {
|
||||
"agent": {
|
||||
"coding_context": "on",
|
||||
"coding_instructions": "Clean the diff before commit.",
|
||||
}
|
||||
}
|
||||
mode = cc.resolve_runtime_mode(platform="cli", cwd=tmp_path, config=cfg)
|
||||
blocks = mode.system_blocks()
|
||||
# The brief stays block 0 (byte-stable, cache-keyed independently); the
|
||||
# operator instructions ride a separate trailing block.
|
||||
assert blocks[0] == cc.CODING_AGENT_GUIDANCE
|
||||
assert any("Clean the diff before commit." in b for b in blocks[1:])
|
||||
|
||||
def test_coding_instructions_accept_a_list(self, tmp_path):
|
||||
_git_init(tmp_path)
|
||||
cfg = {
|
||||
"agent": {
|
||||
"coding_context": "on",
|
||||
"coding_instructions": ["No tsc/lint on UI.", "Clean the diff."],
|
||||
}
|
||||
}
|
||||
mode = cc.resolve_runtime_mode(platform="cli", cwd=tmp_path, config=cfg)
|
||||
instr_block = mode.system_blocks()[-1]
|
||||
assert "No tsc/lint on UI." in instr_block
|
||||
assert "Clean the diff." in instr_block
|
||||
|
||||
def test_no_instructions_block_when_unset(self, tmp_path):
|
||||
_git_init(tmp_path)
|
||||
mode = cc.resolve_runtime_mode(platform="cli", cwd=tmp_path, config={"agent": {"coding_context": "on"}})
|
||||
assert not any("Operator instructions" in b for b in mode.system_blocks())
|
||||
|
||||
def test_toolset_selection_gated_on_focus(self, tmp_path):
|
||||
_git_init(tmp_path)
|
||||
focus = cc.resolve_runtime_mode(platform="cli", cwd=tmp_path, config={"agent": {"coding_context": "focus"}})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue