mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 07:17:54 +08:00
7d29498dfa
AGENTS.md, README, and /status now describe the request-prep cap and the document tools (`read_document` / `search_document`). /status also shows the storage ceiling. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
226 lines
7.0 KiB
Python
226 lines
7.0 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from plyngent.config import (
|
|
DEFAULT_SYSTEM_PROMPT,
|
|
DEFAULT_TOOL_DIRECTIVES,
|
|
compose_agent_system_content,
|
|
load,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
def test_agent_section_defaults(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text("", encoding="utf-8")
|
|
store = load(path)
|
|
assert store.agent_config.system_prompt == DEFAULT_SYSTEM_PROMPT
|
|
assert store.agent_config.tool_directives == DEFAULT_TOOL_DIRECTIVES
|
|
assert store.agent_config.mcp_instructions is True
|
|
assert "professional coding agent" in store.agent_config.system_prompt
|
|
assert "### Workspace" in store.agent_config.tool_directives
|
|
assert store.agent_config.max_tool_result_chars == 32_000
|
|
assert store.agent_config.hard_max_tool_result_chars == 2_000_000
|
|
assert store.agent_config.parallel_tools is True
|
|
assert store.agent_config.confirm_destructive is True
|
|
assert store.agent_config.path_denylist == []
|
|
assert store.agent_config.allow_paths == {}
|
|
assert store.agent_config.auto_continue_limits is False
|
|
assert store.agent_config.max_context_tokens == 200_000
|
|
assert store.agent_config.reasoning_effort == ""
|
|
assert store.agent_config.thinking_budget_tokens == 0
|
|
assert store.plugins_config.enable == []
|
|
assert store.plugins_config.disable == []
|
|
assert store.networking_config.ssrf_assume_public_cidrs == []
|
|
|
|
|
|
def test_networking_ssrf_assume_public_cidrs(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[networking]
|
|
ssrf_assume_public_cidrs = ["198.18.0.0/15", "fdfe:dcba:9876::/48"]
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.networking_config.ssrf_assume_public_cidrs == [
|
|
"198.18.0.0/15",
|
|
"fdfe:dcba:9876::/48",
|
|
]
|
|
assert "ssrf_assume_public_cidrs" in store.networking
|
|
|
|
|
|
def test_compose_defaults_join_persona_and_directives() -> None:
|
|
body = compose_agent_system_content(DEFAULT_SYSTEM_PROMPT, DEFAULT_TOOL_DIRECTIVES)
|
|
assert body is not None
|
|
assert body.startswith("You are a professional coding agent")
|
|
assert "\n\n### Workspace" in body
|
|
assert "### Todos" in body
|
|
# No double-blank-line collapse issues between parts.
|
|
assert "\n\n\n" not in body
|
|
|
|
|
|
def test_compose_empty_combinations() -> None:
|
|
assert compose_agent_system_content("", "") is None
|
|
assert compose_agent_system_content(" ", "\n") is None
|
|
assert compose_agent_system_content("Only persona", "") == "Only persona"
|
|
assert compose_agent_system_content("", "Only tools") == "Only tools"
|
|
assert compose_agent_system_content("Persona", "Tools") == "Persona\n\nTools"
|
|
assert compose_agent_system_content("", "", "") is None
|
|
assert compose_agent_system_content("Persona", "Tools", "Extra") == "Persona\n\nTools\n\nExtra"
|
|
assert compose_agent_system_content("Persona", "", "Extra") == "Persona\n\nExtra"
|
|
|
|
|
|
def test_agent_section_parse(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
system_prompt = "Be brief."
|
|
tool_directives = "Use tools carefully."
|
|
max_tool_result_chars = 100
|
|
parallel_tools = false
|
|
confirm_destructive = false
|
|
path_denylist = ["/secrets/", ".ssh/"]
|
|
max_context_tokens = 5000
|
|
auto_continue_limits = true
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.agent_config.system_prompt == "Be brief."
|
|
assert store.agent_config.tool_directives == "Use tools carefully."
|
|
assert store.agent_config.max_tool_result_chars == 100
|
|
assert store.agent_config.parallel_tools is False
|
|
assert store.agent_config.confirm_destructive is False
|
|
assert store.agent_config.path_denylist == ["/secrets/", ".ssh/"]
|
|
assert store.agent_config.max_context_tokens == 5000
|
|
assert store.agent_config.auto_continue_limits is True
|
|
composed = compose_agent_system_content(
|
|
store.agent_config.system_prompt,
|
|
store.agent_config.tool_directives,
|
|
)
|
|
assert composed == "Be brief.\n\nUse tools carefully."
|
|
|
|
|
|
def test_agent_system_prompt_empty_disables_persona_only(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
system_prompt = ""
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.agent_config.system_prompt == ""
|
|
assert store.agent_config.tool_directives == DEFAULT_TOOL_DIRECTIVES
|
|
body = compose_agent_system_content(
|
|
store.agent_config.system_prompt,
|
|
store.agent_config.tool_directives,
|
|
)
|
|
assert body is not None
|
|
assert "### Workspace" in body
|
|
assert "professional coding agent" not in body
|
|
|
|
|
|
def test_agent_tool_directives_empty_disables_playbook_only(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
tool_directives = ""
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.agent_config.tool_directives == ""
|
|
assert store.agent_config.system_prompt == DEFAULT_SYSTEM_PROMPT
|
|
body = compose_agent_system_content(
|
|
store.agent_config.system_prompt,
|
|
store.agent_config.tool_directives,
|
|
)
|
|
assert body is not None
|
|
assert "professional coding agent" in body
|
|
assert "### Workspace" not in body
|
|
|
|
|
|
def test_agent_both_empty_disables_system(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
system_prompt = ""
|
|
tool_directives = ""
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert (
|
|
compose_agent_system_content(
|
|
store.agent_config.system_prompt,
|
|
store.agent_config.tool_directives,
|
|
)
|
|
is None
|
|
)
|
|
|
|
|
|
def test_agent_allow_paths_parse(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
allow_paths = { "/data/datasets" = "read", "/tmp/build" = "exec" }
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.agent_config.allow_paths == {"/data/datasets": "read", "/tmp/build": "exec"}
|
|
|
|
|
|
def test_agent_allow_paths_invalid_mode_falls_back(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
allow_paths = { "/data" = "sudo" }
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
# Invalid field value resets the whole [agent] section to defaults.
|
|
assert store.agent_config.allow_paths == {}
|
|
|
|
|
|
def test_agent_mcp_instructions_flag(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[agent]
|
|
mcp_instructions = false
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.agent_config.mcp_instructions is False
|
|
|
|
|
|
def test_plugins_section_parse(tmp_path: Path) -> None:
|
|
path = tmp_path / "c.toml"
|
|
_ = path.write_text(
|
|
"""
|
|
[plugins]
|
|
enable = ["acme", "*"]
|
|
disable = ["legacy"]
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
store = load(path)
|
|
assert store.plugins_config.enable == ["acme", "*"]
|
|
assert store.plugins_config.disable == ["legacy"]
|
|
assert store.plugins["enable"] == ["acme", "*"]
|