refactor: 重构 Agent 模块为 AgentScope,删除旧版 CrewAI/LiteLLM 实现
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from enum import Enum
|
||||
from types import SimpleNamespace
|
||||
from typing import Any, cast
|
||||
|
||||
import pytest
|
||||
|
||||
from core.agentscope.events import store as store_module
|
||||
|
||||
|
||||
class _SessionStatus(str, Enum):
|
||||
RUNNING = "running"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
|
||||
|
||||
class _FakeSessionCtx:
|
||||
class _Session:
|
||||
async def commit(self) -> None:
|
||||
return None
|
||||
|
||||
async def __aenter__(self) -> object:
|
||||
return self._Session()
|
||||
|
||||
async def __aexit__(self, exc_type, exc, tb) -> None: # noqa: ANN001
|
||||
del exc_type, exc, tb
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_marks_session_running_on_run_started(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
fake_chat_session = SimpleNamespace(state_snapshot=None)
|
||||
|
||||
class _FakeSessionRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def get_session(self, *, session_id): # noqa: ANN001
|
||||
captured["session_id"] = session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def update_runtime_state(self, **kwargs): # noqa: ANN003
|
||||
captured.update(kwargs)
|
||||
|
||||
monkeypatch.setattr(store_module, "SessionRepository", _FakeSessionRepository)
|
||||
monkeypatch.setattr(store_module, "AgentChatSessionStatus", _SessionStatus)
|
||||
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
|
||||
|
||||
await store.persist(
|
||||
{
|
||||
"type": "RUN_STARTED",
|
||||
"threadId": "00000000-0000-0000-0000-000000000001",
|
||||
"runId": "run-1",
|
||||
}
|
||||
)
|
||||
|
||||
assert captured["status"] == _SessionStatus.RUNNING
|
||||
assert captured["message_delta"] == 0
|
||||
assert captured["token_delta"] == 0
|
||||
assert captured["cost_delta"] == Decimal("0")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_persists_assistant_message_and_aggregates(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
fake_chat_session = SimpleNamespace(state_snapshot={"k": "v"}, message_count=6)
|
||||
|
||||
class _FakeSessionRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def get_session(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def lock_session_for_update(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def update_runtime_state(self, **kwargs): # noqa: ANN003
|
||||
captured.update(kwargs)
|
||||
|
||||
class _FakeMessageRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def append_message(self, **kwargs): # noqa: ANN003
|
||||
captured["append_kwargs"] = kwargs
|
||||
|
||||
monkeypatch.setattr(store_module, "SessionRepository", _FakeSessionRepository)
|
||||
monkeypatch.setattr(store_module, "MessageRepository", _FakeMessageRepository)
|
||||
monkeypatch.setattr(store_module, "AgentChatSessionStatus", _SessionStatus)
|
||||
|
||||
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
|
||||
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_CONTENT",
|
||||
"threadId": "00000000-0000-0000-0000-000000000001",
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
"delta": "hello",
|
||||
}
|
||||
)
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_END",
|
||||
"threadId": "00000000-0000-0000-0000-000000000001",
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
"inputTokens": 3,
|
||||
"outputTokens": 5,
|
||||
"cost": "0.123",
|
||||
"latencyMs": 250,
|
||||
}
|
||||
)
|
||||
|
||||
append_kwargs = cast(dict[str, Any], captured["append_kwargs"])
|
||||
assert append_kwargs["seq"] == 7
|
||||
assert append_kwargs["content"] == "hello"
|
||||
assert append_kwargs["input_tokens"] == 3
|
||||
assert append_kwargs["output_tokens"] == 5
|
||||
assert append_kwargs["cost"] == Decimal("0.123")
|
||||
assert append_kwargs["metadata"]["latency_ms"] == 250
|
||||
assert captured["message_delta"] == 1
|
||||
assert captured["token_delta"] == 8
|
||||
assert captured["cost_delta"] == Decimal("0.123")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_uses_canonical_thread_id_for_buffer_keys(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
fake_chat_session = SimpleNamespace(state_snapshot={}, message_count=1)
|
||||
|
||||
class _FakeSessionRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def get_session(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def lock_session_for_update(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def update_runtime_state(self, **kwargs): # noqa: ANN003
|
||||
captured.update(kwargs)
|
||||
|
||||
class _FakeMessageRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def append_message(self, **kwargs): # noqa: ANN003
|
||||
captured["append_kwargs"] = kwargs
|
||||
|
||||
monkeypatch.setattr(store_module, "SessionRepository", _FakeSessionRepository)
|
||||
monkeypatch.setattr(store_module, "MessageRepository", _FakeMessageRepository)
|
||||
monkeypatch.setattr(store_module, "AgentChatSessionStatus", _SessionStatus)
|
||||
|
||||
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
|
||||
compact_thread_id = "00000000000000000000000000000001"
|
||||
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_CONTENT",
|
||||
"threadId": compact_thread_id,
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
"delta": "hello",
|
||||
}
|
||||
)
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_END",
|
||||
"threadId": compact_thread_id,
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
}
|
||||
)
|
||||
|
||||
append_kwargs = cast(dict[str, Any], captured["append_kwargs"])
|
||||
assert append_kwargs["content"] == "hello"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_clears_buffer_on_run_finished(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
fake_chat_session = SimpleNamespace(state_snapshot={}, message_count=0)
|
||||
|
||||
class _FakeSessionRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def get_session(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def lock_session_for_update(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return fake_chat_session
|
||||
|
||||
async def update_runtime_state(self, **kwargs): # noqa: ANN003
|
||||
captured.update(kwargs)
|
||||
|
||||
class _FakeMessageRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def append_message(self, **kwargs): # noqa: ANN003
|
||||
captured["append_kwargs"] = kwargs
|
||||
|
||||
monkeypatch.setattr(store_module, "SessionRepository", _FakeSessionRepository)
|
||||
monkeypatch.setattr(store_module, "MessageRepository", _FakeMessageRepository)
|
||||
monkeypatch.setattr(store_module, "AgentChatSessionStatus", _SessionStatus)
|
||||
|
||||
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
|
||||
thread_id = "00000000-0000-0000-0000-000000000001"
|
||||
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_CONTENT",
|
||||
"threadId": thread_id,
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
"delta": "stale",
|
||||
}
|
||||
)
|
||||
await store.persist(
|
||||
{
|
||||
"type": "RUN_FINISHED",
|
||||
"threadId": thread_id,
|
||||
"runId": "run-1",
|
||||
}
|
||||
)
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_END",
|
||||
"threadId": thread_id,
|
||||
"runId": "run-1",
|
||||
"messageId": "assistant-run-1",
|
||||
}
|
||||
)
|
||||
|
||||
assert "append_kwargs" not in captured
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_store_drops_buffer_when_session_missing(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
class _FakeSessionRepository:
|
||||
def __init__(self, session: object) -> None:
|
||||
del session
|
||||
|
||||
async def get_session(self, *, session_id): # noqa: ANN001
|
||||
del session_id
|
||||
return None
|
||||
|
||||
monkeypatch.setattr(store_module, "SessionRepository", _FakeSessionRepository)
|
||||
|
||||
store = store_module.SqlAlchemyEventStore(session_factory=lambda: _FakeSessionCtx())
|
||||
thread_id = "00000000-0000-0000-0000-000000000001"
|
||||
|
||||
await store.persist(
|
||||
{
|
||||
"type": "TEXT_MESSAGE_CONTENT",
|
||||
"threadId": thread_id,
|
||||
"messageId": "assistant-run-1",
|
||||
"delta": "orphan",
|
||||
}
|
||||
)
|
||||
|
||||
assert store._message_buffers == {}
|
||||
@@ -0,0 +1,163 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from core.agentscope.persistence.user_context_cache import UserContextCache
|
||||
from core.agentscope.schemas.user_context import (
|
||||
UserAgentContext,
|
||||
parse_profile_settings,
|
||||
)
|
||||
|
||||
|
||||
class _FakeRedis:
|
||||
def __init__(self) -> None:
|
||||
self.store: dict[str, dict[str, str]] = {}
|
||||
self.set_store: dict[str, set[str]] = {}
|
||||
self.expire_calls: list[tuple[str, int]] = []
|
||||
self.delete_calls: list[str] = []
|
||||
self.hincrby_calls: list[tuple[str, str, int]] = []
|
||||
|
||||
async def hgetall(self, key: str) -> dict[str, str]:
|
||||
return dict(self.store.get(key, {}))
|
||||
|
||||
async def hset(self, key: str, mapping: dict[str, str]) -> int:
|
||||
self.store[key] = dict(mapping)
|
||||
return 1
|
||||
|
||||
async def hincrby(self, key: str, field: str, amount: int = 1) -> int:
|
||||
self.hincrby_calls.append((key, field, amount))
|
||||
data = self.store.setdefault(key, {})
|
||||
current = int(data.get(field, "0"))
|
||||
next_value = current + amount
|
||||
data[field] = str(next_value)
|
||||
return next_value
|
||||
|
||||
async def expire(self, key: str, seconds: int) -> int:
|
||||
self.expire_calls.append((key, seconds))
|
||||
return 1
|
||||
|
||||
async def delete(self, *keys: str) -> int:
|
||||
for key in keys:
|
||||
self.delete_calls.append(key)
|
||||
self.store.pop(key, None)
|
||||
self.set_store.pop(key, None)
|
||||
return len(keys)
|
||||
|
||||
async def sadd(self, key: str, *values: str) -> int:
|
||||
bucket = self.set_store.setdefault(key, set())
|
||||
before = len(bucket)
|
||||
for value in values:
|
||||
bucket.add(value)
|
||||
return len(bucket) - before
|
||||
|
||||
async def smembers(self, key: str) -> set[str]:
|
||||
return set(self.set_store.get(key, set()))
|
||||
|
||||
|
||||
class _BrokenRedis:
|
||||
async def hgetall(self, key: str) -> dict[str, str]:
|
||||
del key
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def hset(self, key: str, mapping: dict[str, str]) -> int:
|
||||
del key, mapping
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def hincrby(self, key: str, field: str, amount: int = 1) -> int:
|
||||
del key, field, amount
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def expire(self, key: str, seconds: int) -> int:
|
||||
del key, seconds
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def delete(self, *keys: str) -> int:
|
||||
del keys
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def sadd(self, key: str, *values: str) -> int:
|
||||
del key, values
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
async def smembers(self, key: str) -> set[str]:
|
||||
del key
|
||||
raise RuntimeError("redis down")
|
||||
|
||||
|
||||
def _build_context() -> UserAgentContext:
|
||||
return UserAgentContext(
|
||||
user_id=uuid4(),
|
||||
username="demo-user",
|
||||
bio="demo bio",
|
||||
settings=parse_profile_settings({"preferences": {"ai_language": "en-US"}}),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_context_cache_set_and_get_hit() -> None:
|
||||
redis = _FakeRedis()
|
||||
cache = UserContextCache(
|
||||
client=redis,
|
||||
key_prefix="agent:user-context",
|
||||
ttl_seconds=600,
|
||||
max_turns=3,
|
||||
)
|
||||
session_id = uuid4()
|
||||
context = _build_context()
|
||||
|
||||
await cache.set(session_id=session_id, context=context)
|
||||
loaded = await cache.get(session_id=session_id)
|
||||
|
||||
assert loaded is not None
|
||||
assert loaded.user_id == context.user_id
|
||||
assert loaded.username == "demo-user"
|
||||
assert redis.expire_calls == [
|
||||
(f"agent:user-context:{session_id}", 600),
|
||||
(f"agent:user-context:sessions:{context.user_id}", 600),
|
||||
]
|
||||
assert redis.hincrby_calls == [
|
||||
(f"agent:user-context:{session_id}", "turns_used", 1)
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_context_cache_invalidate_user_deletes_all_sessions() -> None:
|
||||
redis = _FakeRedis()
|
||||
cache = UserContextCache(
|
||||
client=redis,
|
||||
key_prefix="agent:user-context",
|
||||
ttl_seconds=600,
|
||||
max_turns=3,
|
||||
)
|
||||
context = _build_context()
|
||||
s1 = uuid4()
|
||||
s2 = uuid4()
|
||||
|
||||
await cache.set(session_id=s1, context=context)
|
||||
await cache.set(session_id=s2, context=context)
|
||||
|
||||
deleted = await cache.invalidate_user(user_id=context.user_id)
|
||||
|
||||
assert deleted == 2
|
||||
assert f"agent:user-context:{s1}" in redis.delete_calls
|
||||
assert f"agent:user-context:{s2}" in redis.delete_calls
|
||||
assert f"agent:user-context:sessions:{context.user_id}" in redis.delete_calls
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_user_context_cache_degrades_gracefully_on_redis_error() -> None:
|
||||
cache = UserContextCache(
|
||||
client=_BrokenRedis(),
|
||||
key_prefix="agent:user-context",
|
||||
ttl_seconds=600,
|
||||
max_turns=3,
|
||||
)
|
||||
session_id = uuid4()
|
||||
context = _build_context()
|
||||
|
||||
loaded = await cache.get(session_id=session_id)
|
||||
await cache.set(session_id=session_id, context=context)
|
||||
|
||||
assert loaded is None
|
||||
@@ -6,7 +6,10 @@ from uuid import uuid4
|
||||
import pytest
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.agent.domain.user_context import UserAgentContext, parse_profile_settings
|
||||
from core.agentscope.schemas.user_context import (
|
||||
UserAgentContext,
|
||||
parse_profile_settings,
|
||||
)
|
||||
from core.agentscope.runtime.agent_route_runtime import AgentRouteRuntime
|
||||
from core.agentscope.schemas import ReportOutput, RuntimeOutput
|
||||
from core.agentscope.schemas.agent_runtime import RunCommand
|
||||
|
||||
@@ -7,8 +7,11 @@ from uuid import uuid4
|
||||
import pytest
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.agent.domain.system_agent_config import SystemAgentLLMConfig
|
||||
from core.agent.domain.user_context import UserAgentContext, parse_profile_settings
|
||||
from core.agentscope.schemas.system_agent_config import SystemAgentLLMConfig
|
||||
from core.agentscope.schemas.user_context import (
|
||||
UserAgentContext,
|
||||
parse_profile_settings,
|
||||
)
|
||||
from core.agentscope.runtime.config_loader import RuntimeStageConfig
|
||||
from core.agentscope.runtime.orchestrator import AgentScopeRuntimeOrchestrator
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from core.agent.domain.system_agent_config import SystemAgentLLMConfig
|
||||
from core.agentscope.schemas.system_agent_config import SystemAgentLLMConfig
|
||||
from core.agentscope.runtime.config_loader import RuntimeStageConfig
|
||||
from core.agentscope.runtime.react_runner import (
|
||||
AgentScopeReActRunner,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from core.agentscope.schemas.agui_input import (
|
||||
MAX_MESSAGES,
|
||||
MAX_RUN_ID_LENGTH,
|
||||
MAX_RUN_INPUT_BYTES,
|
||||
MAX_TEXT_CHARS,
|
||||
extract_latest_tool_result,
|
||||
parse_run_input,
|
||||
validate_run_request_messages_contract,
|
||||
)
|
||||
|
||||
|
||||
def _base_payload() -> dict[str, object]:
|
||||
return {
|
||||
"threadId": "00000000-0000-0000-0000-000000000001",
|
||||
"runId": "run-1",
|
||||
"state": {},
|
||||
"messages": [{"id": "u1", "role": "user", "content": "hello"}],
|
||||
"tools": [],
|
||||
"context": [],
|
||||
"forwardedProps": {},
|
||||
}
|
||||
|
||||
|
||||
def test_parse_run_input_rejects_invalid_uuid() -> None:
|
||||
payload = _base_payload()
|
||||
payload["threadId"] = "bad-uuid"
|
||||
|
||||
with pytest.raises(ValueError, match="threadId must be a valid UUID"):
|
||||
parse_run_input(payload)
|
||||
|
||||
|
||||
def test_parse_run_input_rejects_message_count_over_limit() -> None:
|
||||
payload = _base_payload()
|
||||
payload["messages"] = [
|
||||
{"id": f"u{i}", "role": "user", "content": "x"} for i in range(MAX_MESSAGES + 1)
|
||||
]
|
||||
|
||||
with pytest.raises(ValueError, match="RunAgentInput.messages exceeds limit"):
|
||||
parse_run_input(payload)
|
||||
|
||||
|
||||
def test_parse_run_input_rejects_user_text_over_limit() -> None:
|
||||
payload = _base_payload()
|
||||
payload["messages"] = [
|
||||
{"id": "u1", "role": "user", "content": "x" * (MAX_TEXT_CHARS + 1)}
|
||||
]
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match="RunAgentInput user message text exceeds limit"
|
||||
):
|
||||
parse_run_input(payload)
|
||||
|
||||
|
||||
def test_parse_run_input_rejects_payload_over_limit() -> None:
|
||||
payload = _base_payload()
|
||||
payload["forwardedProps"] = {"blob": "x" * MAX_RUN_INPUT_BYTES}
|
||||
|
||||
with pytest.raises(ValueError, match="RunAgentInput payload exceeds size limit"):
|
||||
parse_run_input(payload)
|
||||
|
||||
|
||||
def test_parse_run_input_rejects_run_id_over_limit() -> None:
|
||||
payload = _base_payload()
|
||||
payload["runId"] = "r" * (MAX_RUN_ID_LENGTH + 1)
|
||||
|
||||
with pytest.raises(ValueError, match="runId exceeds length limit"):
|
||||
parse_run_input(payload)
|
||||
|
||||
|
||||
def test_extract_latest_tool_result_requires_tool_call_id() -> None:
|
||||
run_input = parse_run_input(_base_payload())
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="RunAgentInput.messages requires a tool message with toolCallId for resume",
|
||||
):
|
||||
extract_latest_tool_result(run_input)
|
||||
|
||||
|
||||
def test_validate_run_request_messages_contract_requires_single_user_message() -> None:
|
||||
payload = _base_payload()
|
||||
payload["messages"] = [
|
||||
{"id": "u1", "role": "user", "content": "hello"},
|
||||
{"id": "u2", "role": "user", "content": "again"},
|
||||
]
|
||||
run_input = parse_run_input(payload)
|
||||
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match="RunAgentInput.messages must contain exactly one user message",
|
||||
):
|
||||
validate_run_request_messages_contract(run_input)
|
||||
@@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def test_active_agentscope_paths_do_not_import_core_agent() -> None:
|
||||
root = Path(__file__).resolve().parents[4]
|
||||
targets = [
|
||||
root / "src" / "core" / "agentscope",
|
||||
root / "src" / "v1" / "agent",
|
||||
]
|
||||
|
||||
offenders: list[str] = []
|
||||
for target in targets:
|
||||
for py_file in target.rglob("*.py"):
|
||||
text = py_file.read_text(encoding="utf-8")
|
||||
if "core.agent." in text:
|
||||
offenders.append(str(py_file.relative_to(root)))
|
||||
|
||||
assert offenders == []
|
||||
|
||||
|
||||
def test_active_app_paths_do_not_import_core_agent() -> None:
|
||||
root = Path(__file__).resolve().parents[4]
|
||||
targets = [
|
||||
root / "src" / "v1" / "users" / "service.py",
|
||||
root / "src" / "core" / "config" / "initial" / "init_data.py",
|
||||
]
|
||||
|
||||
offenders: list[str] = []
|
||||
for target in targets:
|
||||
text = target.read_text(encoding="utf-8")
|
||||
if "core.agent." in text:
|
||||
offenders.append(str(target.relative_to(root)))
|
||||
|
||||
assert offenders == []
|
||||
@@ -3,7 +3,10 @@ from __future__ import annotations
|
||||
from datetime import datetime, timezone
|
||||
from uuid import uuid4
|
||||
|
||||
from core.agent.domain.user_context import UserAgentContext, parse_profile_settings
|
||||
from core.agentscope.schemas.user_context import (
|
||||
UserAgentContext,
|
||||
parse_profile_settings,
|
||||
)
|
||||
from core.agentscope.prompts.system_prompt import build_system_prompt
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user