Ctrl K
ComunidadGuías…

tests/agents/test_subagents.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""The built-in agents: Claude Code's Explore, Plan and general-purpose with
their tool sets, main's agent types from every described agent."""

from __future__ import annotations

from typing import Any

from noeta.agents import builtin_agent_files, default_agents
from noeta.agents.agent_files import parse_agent_file
from noeta.core.agent import Agent
from noeta.core.extension import TaskView
from noeta.core.loop.state import TaskState
from noeta.plugins.mcp import Mcp
from noeta.plugins.subtasks import Subtasks


def _agents(**kw: Any) -> dict[str, Agent]:
    return {a.name: a for a in default_agents("m", **kw)}


def _tools(agent: Agent, agents: dict[str, Agent], *, child: bool = True) -> list[str]:
    state = TaskState(agent=agent.name, parent_id="p" if child else None,
                      config={"subagent_type": agent.name} if child else {})
    view = TaskView(state=state, agents=agents)
    names = [t.name for e in agent.all_extensions() for t in e.tools(view)]
    return [n for n in names if (agent.allowed_tools is None or n in agent.allowed_tools)
            and n not in agent.denied_tools]


def test_built_in_agent_files() -> None:
    names = [f.name for f in builtin_agent_files()]
    assert names == ["main", "Explore", "general-purpose", "Plan"]


def test_tool_sets() -> None:
    agents = _agents()
    gp = _tools(agents["general-purpose"], agents)
    assert {"Agent", "Bash", "Edit", "Read", "Write", "SendMessage"} <= set(gp)
    assert gp[-1] == "SubagentHandback" and "ListAgents" not in gp
    for name in ("Explore", "Plan"):
        tools = _tools(agents[name], agents)
        assert {"Bash", "Read", "SendMessage"} <= set(tools)
        assert not {"Edit", "Write", "Agent", "AskUserQuestion", "ListAgents"} & set(tools)
        assert tools[-1] == "SubagentHandback"
        assert agents[name].denied_tools == ("Agent", "ExitPlanMode", "Edit", "Write",
                                             "NotebookEdit")
    main = _tools(agents["main"], agents, child=False)
    assert {"Agent", "ListAgents", "SendMessage"} <= set(main)
    assert "SubagentHandback" not in main


def test_main_agent_types_come_from_described_agents() -> None:
    agents = _agents()
    [sub] = [e for e in agents["main"].extensions if isinstance(e, Subtasks)]
    roster = sub.roster_for(TaskView(state=TaskState(agent="main"), agents=agents))
    assert sorted(roster) == ["Explore", "Plan", "general-purpose"]
    assert roster["Explore"].tools == ("All tools except Agent, ExitPlanMode, Edit, Write, "
                                       "NotebookEdit")
    assert roster["general-purpose"].tools == "*"
    assert roster["Explore"].description.startswith("Read-only search agent")


def test_extension_sets_and_sharing() -> None:
    agents = _agents(plugins={"mcp": Mcp()})
    names = {n: {e.name for e in a.all_extensions()} for n, a in agents.items()}
    common = {"compaction", "permissions", "shell", "web", "environment", "skills", "mcp"}
    assert common | {"instructions"} <= names["general-purpose"]
    for name in ("Explore", "Plan"):
        assert common <= names[name]
        # Claude Code's omitClaudeMd: only the machine's managed files.
        [instructions] = [e for e in agents[name].all_extensions() if e.name == "instructions"]
        assert getattr(instructions, "managed_only", False)
    assert "memory" not in names["main"]  # memory is off until set
    shells = {id(e) for a in agents.values() for e in a.extensions if e.name == "shell"}
    assert len(shells) == 1


def test_main_kw_and_extra_files() -> None:
    reviewer = parse_agent_file(
        "---\nname: reviewer\ndescription: Reviews diffs.\ntools: Read, Grep\n---\nReview.\n")
    agents = {a.name: a for a in default_agents("m", extra_files=[reviewer],
                                               system_prompt="Short.\n")}
    assert agents["main"].system_prompt == "Short.\n"
    r = agents["reviewer"]
    assert r.system_prompt == "Review.\n" and r.allowed_tools == ("Read", "Grep")
    assert {e.name for e in r.extensions} >= {"fs", "shell", "subtasks"}
    [sub] = [e for e in agents["main"].extensions if isinstance(e, Subtasks)]
    roster = sub.roster_for(TaskView(state=TaskState(agent="main"), agents=agents))
    assert roster["reviewer"].tools == "Read, Grep"


def test_explore_runs_on_opus_under_a_fable_caller() -> None:
    """Claude Code's Explore ``inheritCap: "opus"``: a caller on a family
    above Opus (Fable) gets its Explore on Opus; only the built-in file."""
    from noeta.plugins.subtasks.roster import MODEL_CAP_KEY, capped_model

    agents = _agents()
    assert agents["Explore"].extra["inheritCap"] == "opus"
    assert "inheritCap" not in agents["Plan"].extra
    assert capped_model("claude-fable-5-1", "opus") == "claude-opus-5-5"
    assert capped_model("fable", "opus") == "claude-opus-5-5"
    for model in ("claude-opus-5-5", "claude-sonnet-5-5", "anthropic.claude-fable-5-1",
                  "gpt-5", ""):
        assert capped_model(model, "opus") is None
    sub = Subtasks()
    state = TaskState(agent="main", config={"model": "claude-fable-5-1"})
    ctx: Any = None
    capped = sub.child_config(state, ctx, "Explore", {MODEL_CAP_KEY: "opus"}, "Explore", {},
                              fork=False)
    assert capped["model"] == "claude-opus-5-5" and MODEL_CAP_KEY not in capped
    asked = sub.child_config(state, ctx, "Explore", {MODEL_CAP_KEY: "opus"}, "Explore",
                             {"model": "haiku"}, fork=False)
    assert asked["model"] == "claude-haiku-5-5"
    plain = sub.child_config(TaskState(agent="main"), ctx, "Explore", {MODEL_CAP_KEY: "opus"},
                             "Explore", {}, fork=False, parent_model="claude-fable-5-1")
    assert plain["model"] == "claude-opus-5-5"
    user_file = parse_agent_file("---\nname: Explore\ndescription: mine\n---\nlook")
    explores = [a for a in default_agents("m", extra_files=[user_file]) if a.name == "Explore"]
    assert explores and all(a.description != "mine" or "inheritCap" not in a.extra
                            for a in explores)
    assert any(a.description == "mine" for a in explores)


def test_the_plan_agents_prompt_looks_for_similar_features_and_ends_read_only() -> None:
    """Claude Code's Plan prompt: the exploring step looks for similar
    features to use as a reference, and a closing reminder after the report
    format repeats that it only explores and plans."""
    prompt = str(_agents()["Plan"].system_prompt)
    explore = next(line for line in prompt.splitlines() if line.startswith("2. Explore"))
    assert "similar features" in explore
    critical = prompt.index("3-5 files most critical")
    closing = prompt.index("Remember: you only explore and plan.")
    assert critical < closing
    assert "must not write, edit or change any file" in prompt[closing:]