Spaces:
Running
Running
File size: 13,058 Bytes
3193174 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | from unittest.mock import patch
import torch
from core.agent import (
AgentLLMConfig,
AgentProfile,
TaskNode,
extract_agent_profiles,
)
class TestAgentLLMConfig:
"""LLM agent configuration."""
def test_resolve_api_key_from_env(self):
"""resolve_api_key reads key from environment variable."""
cfg = AgentLLMConfig(api_key="$MY_KEY")
with patch.dict("os.environ", {"MY_KEY": "secret123"}):
assert cfg.resolve_api_key() == "secret123"
def test_resolve_api_key_direct(self):
"""resolve_api_key returns direct key value."""
cfg = AgentLLMConfig(api_key="sk-abc")
assert cfg.resolve_api_key() == "sk-abc"
def test_resolve_api_key_none(self):
"""resolve_api_key returns None when no key is set."""
cfg = AgentLLMConfig()
assert cfg.resolve_api_key() is None
def test_is_configured(self):
"""is_configured: True when model_name or base_url is set."""
assert AgentLLMConfig().is_configured() is False
assert AgentLLMConfig(model_name="gpt-4").is_configured() is True
assert AgentLLMConfig(base_url="http://localhost").is_configured() is True
def test_to_generation_params_full(self):
"""to_generation_params with all parameters set."""
cfg = AgentLLMConfig(
max_tokens=100,
temperature=0.7,
top_p=0.9,
stop_sequences=["END"],
extra_params={"seed": 42},
)
params = cfg.to_generation_params()
assert params["max_tokens"] == 100
assert params["temperature"] == 0.7
assert params["top_p"] == 0.9
assert params["stop"] == ["END"]
assert params["seed"] == 42
def test_to_generation_params_empty(self):
"""to_generation_params returns empty dict when no params are set."""
assert AgentLLMConfig().to_generation_params() == {}
class TestAgentProfile:
"""Agent profile — methods and serialization."""
def test_defaults(self):
"""Default values of agent profile fields."""
p = AgentProfile(agent_id="a1", display_name="Agent 1")
assert p.persona == ""
assert p.description == ""
assert p.llm_backbone is None
assert p.llm_config is None
assert p.tools == []
assert p.embedding is None
assert p.state == []
assert p.hidden_state is None
assert p.input_schema is None
assert p.output_schema is None
def test_role_property(self):
"""Role property is an alias for agent_id."""
p = AgentProfile(agent_id="writer", display_name="Writer")
assert p.role == "writer"
def test_has_tools(self):
"""has_tools returns True only when tools list is non-empty."""
assert AgentProfile(agent_id="a", display_name="A").has_tools() is False
assert AgentProfile(agent_id="a", display_name="A", tools=["search"]).has_tools() is True
def test_get_tool_names_strings(self):
"""get_tool_names returns string tool names as-is."""
p = AgentProfile(agent_id="a", display_name="A", tools=["search", "calc"])
assert p.get_tool_names() == ["search", "calc"]
def test_get_model_name_from_config(self):
"""get_model_name reads model name from llm_config."""
cfg = AgentLLMConfig(model_name="gpt-4")
p = AgentProfile(agent_id="a", display_name="A", llm_config=cfg)
assert p.get_model_name() == "gpt-4"
def test_get_model_name_from_backbone(self):
"""get_model_name falls back to llm_backbone."""
p = AgentProfile(agent_id="a", display_name="A", llm_backbone="claude-3")
assert p.get_model_name() == "claude-3"
def test_get_llm_config_existing(self):
"""get_llm_config returns the existing config object."""
cfg = AgentLLMConfig(model_name="gpt-4")
p = AgentProfile(agent_id="a", display_name="A", llm_config=cfg)
assert p.get_llm_config() is cfg
def test_get_llm_config_default(self):
"""get_llm_config creates a default config from llm_backbone."""
p = AgentProfile(agent_id="a", display_name="A", llm_backbone="claude-3")
result = p.get_llm_config()
assert isinstance(result, AgentLLMConfig)
assert result.model_name == "claude-3"
def test_has_custom_llm(self):
"""has_custom_llm returns True only when llm_config is set and configured."""
assert AgentProfile(agent_id="a", display_name="A").has_custom_llm() is False
cfg = AgentLLMConfig(model_name="gpt-4")
assert AgentProfile(agent_id="a", display_name="A", llm_config=cfg).has_custom_llm() is True
def test_with_llm_config(self):
"""with_llm_config returns an immutable copy with the new config."""
p = AgentProfile(agent_id="a", display_name="A")
cfg = AgentLLMConfig(model_name="gpt-4")
p2 = p.with_llm_config(cfg)
assert p2.llm_config is cfg
assert p.llm_config is None
def test_with_embedding(self):
"""with_embedding returns a copy with the given embedding tensor."""
p = AgentProfile(agent_id="a", display_name="A")
emb = torch.randn(16)
p2 = p.with_embedding(emb)
assert p2.embedding is emb
assert p.embedding is None
def test_state_methods(self):
"""with_state, append_state, and clear_state work immutably."""
p = AgentProfile(agent_id="a", display_name="A")
p2 = p.with_state([{"role": "user", "content": "hi"}])
assert len(p2.state) == 1
assert p.state == []
p3 = p2.append_state({"role": "assistant", "content": "hello"})
assert len(p3.state) == 2
assert len(p2.state) == 1
p4 = p3.clear_state()
assert p4.state == []
assert len(p3.state) == 2
def test_to_text(self):
"""to_text produces a human-readable profile representation."""
p = AgentProfile(
agent_id="a",
display_name="Writer",
persona="a creative writer",
description="Writes stories",
tools=["search"],
llm_backbone="gpt-4",
)
text = p.to_text()
assert "Writer" in text
assert "a creative writer" in text
assert "Writes stories" in text
assert "Tools: search" in text
assert "LLM Backbone: gpt-4" in text
def test_to_dict(self):
"""to_dict serializes the profile to a dictionary."""
emb = torch.tensor([1.0, 2.0])
cfg = AgentLLMConfig(model_name="gpt-4")
p = AgentProfile(
agent_id="a",
display_name="A",
persona="test",
embedding=emb,
llm_config=cfg,
)
d = p.to_dict()
assert d["agent_id"] == "a"
assert d["display_name"] == "A"
assert d["persona"] == "test"
assert d["embedding"] == [1.0, 2.0]
assert "llm_config" in d
assert d["llm_config"]["model_name"] == "gpt-4"
class TestTaskNode:
"""Virtual task node."""
def test_defaults(self):
"""Default fields of TaskNode."""
t = TaskNode(query="Solve X")
assert t.agent_id == "__task__"
assert t.type == "task"
assert t.query == "Solve X"
assert t.display_name == "Task"
assert t.persona == ""
assert t.embedding is None
assert t.tools == []
assert t.state == []
def test_to_text(self):
"""to_text includes description and query."""
t = TaskNode(query="Solve X", description="Important task")
text = t.to_text()
assert "Important task" in text
assert "Task: Solve X" in text
def test_to_text_empty_query(self):
"""to_text shows (unspecified) for blank query."""
t = TaskNode(query=" ")
assert "(unspecified)" in t.to_text()
def test_with_embedding(self):
"""with_embedding returns a copy with the given embedding tensor."""
t = TaskNode(query="Q")
emb = torch.randn(8)
t2 = t.with_embedding(emb)
assert t2.embedding is emb
assert t.embedding is None
class TestExtractAgentProfiles:
"""Parsing agents from a dictionary."""
def test_basic_extraction(self):
"""Basic parsing from agents_data dict."""
data = {
"agents": [
{"agent": {"role": "writer", "name": "Writer", "persona": "writes"}},
{"agent": {"role": "reviewer", "name": "Reviewer"}},
]
}
profiles = extract_agent_profiles(data)
assert len(profiles) == 2
assert profiles[0].agent_id == "writer"
assert profiles[0].display_name == "Writer"
assert profiles[1].agent_id == "reviewer"
def test_duplicate_agents(self):
"""Duplicate roles — first occurrence is kept."""
data = {
"agents": [
{"agent": {"role": "writer", "name": "First"}},
{"agent": {"role": "writer", "name": "Second"}},
]
}
profiles = extract_agent_profiles(data)
assert len(profiles) == 1
assert profiles[0].display_name == "First"
def test_invalid_entries(self):
"""Invalid entries are silently skipped."""
data = {
"agents": [
"not a dict",
{"agent": "not a dict either"},
{"agent": {"no_role": True}},
{"agent": {"role": "valid", "name": "OK"}},
]
}
profiles = extract_agent_profiles(data)
assert len(profiles) == 1
assert profiles[0].agent_id == "valid"
def test_tools_extraction(self):
"""Tools are extracted from various formats and deduplicated."""
data = {
"agents": [
{
"agent": {
"role": "a1",
"name": "A",
"tools": [
"search",
{"name": "calc"},
{"tool": "browser"},
42,
"search",
],
}
}
]
}
profiles = extract_agent_profiles(data)
tools = profiles[0].tools
assert "search" in tools
assert "calc" in tools
assert "browser" in tools
assert len(tools) == 3
def test_llm_backbone_extraction(self):
"""LLM backbone is extracted from various field formats."""
data_str = {"agents": [{"agent": {"role": "a", "name": "A", "llm": "gpt-4"}}]}
p1 = extract_agent_profiles(data_str)
assert p1[0].llm_backbone == "gpt-4"
data_dict = {"agents": [{"agent": {"role": "b", "name": "B", "model": {"name": "claude-3"}}}]}
p2 = extract_agent_profiles(data_dict)
assert p2[0].llm_backbone == "claude-3"
class TestAgentProfileMissingCoverage:
"""Tests for missing lines in core/agent.py."""
def test_get_tool_names_with_base_tool_object(self):
"""get_tool_names when tools contains BaseTool objects (lines 143-144)."""
from tools.shell import ShellTool
shell = ShellTool()
agent = AgentProfile(agent_id="test", display_name="Test", tools=[shell])
names = agent.get_tool_names()
assert "shell" in names
def test_get_tool_objects_with_base_tool_object(self):
"""get_tool_objects when tools contains BaseTool objects (lines 182-183)."""
from tools.shell import ShellTool
shell = ShellTool()
agent = AgentProfile(agent_id="test", display_name="Test", tools=[shell])
objects = agent.get_tool_objects()
assert shell in objects
def test_with_hidden_state(self):
"""with_hidden_state returns updated copy (line 240)."""
agent = AgentProfile(agent_id="test", display_name="Test")
hidden = torch.zeros(10)
new_agent = agent.with_hidden_state(hidden)
assert new_agent.hidden_state is not None
assert torch.equal(new_agent.hidden_state, hidden)
def test_to_dict_with_schemas(self):
"""to_dict includes llm_config, input_schema, output_schema (lines 266, 268)."""
agent = AgentProfile(
agent_id="test",
display_name="Test",
llm_config=AgentLLMConfig(model_name="gpt-4"),
input_schema={"type": "object"},
output_schema={"type": "string"},
)
d = agent.to_dict()
assert "llm_config" in d
assert "input_schema" in d
assert "output_schema" in d
def test_extract_llm_backbone_dict_no_model_name_type(self):
"""_extract_llm_backbone when candidate is a dict with no model/name/type key (line 366)."""
from core.agent import _extract_llm_backbone
result = _extract_llm_backbone({"llm": {"unknown_key": "value"}})
assert result is None
|