refactor(agent): remove memory agent, simplify runtime config system

This commit is contained in:
zl-q
2026-03-23 01:20:27 +08:00
parent 80ad5141a6
commit 3aacc756db
43 changed files with 1210 additions and 1312 deletions
@@ -5,17 +5,23 @@ from uuid import UUID, uuid4
import pytest
from core.automation.scheduler import (
AutomationSchedulerService,
_compute_next_run_at,
from models.automation_jobs import AutomationJob as OrmAutomationJob, ScheduleType
from schemas.automation import (
RuntimeConfig,
)
from models.automation_jobs import ScheduleType
from schemas.automation.config import AutomationJobConfig
from schemas.automation.scheduler import DueAutomationJob
from v1.automation_jobs.service import AutomationJobsService, _compute_next_run_at
class _FakeSession:
async def commit(self) -> None:
pass
async def rollback(self) -> None:
pass
class _FakeRepository:
def __init__(self, jobs: list[DueAutomationJob]) -> None:
def __init__(self, jobs: list[OrmAutomationJob]) -> None:
self.jobs = jobs
self.marked: list[tuple[UUID, datetime, datetime]] = []
self.commits = 0
@@ -23,30 +29,14 @@ class _FakeRepository:
async def list_due_jobs(
self, *, now_utc: datetime, limit: int
) -> list[DueAutomationJob]:
) -> list[OrmAutomationJob]:
del now_utc
return self.jobs[:limit]
async def get_job_config(self, *, job_id: UUID) -> AutomationJobConfig:
del job_id
return AutomationJobConfig.model_validate(
{
"agent_type": "memory",
"model_code": "qwen3.5-flash",
"enabled_tools": ["calendar.read", "user.lookup"],
"input_template": "auto input",
"context": {
"source": "latest_chat",
"window_mode": "day",
"window_count": 2,
},
}
)
async def ensure_latest_chat_session(self, *, owner_id: UUID) -> UUID:
async def get_or_create_chat_session(self, *, owner_id: UUID) -> UUID:
return owner_id
async def mark_job_dispatched(
async def update_job_schedule(
self,
*,
job_id: UUID,
@@ -55,57 +45,65 @@ class _FakeRepository:
) -> None:
self.marked.append((job_id, next_run_at, last_run_at))
async def commit(self) -> None:
self.commits += 1
async def rollback(self) -> None:
self.rollbacks += 1
class _FakeQueue:
def __init__(self) -> None:
self.commands: list[dict[str, object]] = []
async def enqueue(
self,
*,
command: dict[str, object],
dedup_key: str | None,
) -> str:
del dedup_key
self.commands.append(command)
return "task-1"
def _make_orm_job(
*,
job_id: UUID | None = None,
owner_id: UUID | None = None,
schedule_type: ScheduleType = ScheduleType.DAILY,
next_run_at: datetime | None = None,
) -> OrmAutomationJob:
now = datetime(2026, 3, 19, 12, 0, tzinfo=timezone.utc)
return OrmAutomationJob(
id=job_id or uuid4(),
owner_id=owner_id or uuid4(),
title="Test Job",
config={
"enabled_tools": ["calendar.read", "user.lookup"],
"context": {
"source": "latest_chat",
"window_mode": "day",
"window_count": 2,
},
"input_template": "auto input: {date}",
},
schedule_type=schedule_type,
run_at=now - timedelta(hours=1),
next_run_at=next_run_at or now - timedelta(minutes=1),
timezone="UTC",
last_run_at=None,
status="active",
created_by=None,
created_at=now - timedelta(days=1),
updated_at=now - timedelta(hours=1),
deleted_at=None,
)
@pytest.mark.asyncio
async def test_scan_and_dispatch_enqueues_memory_run_command() -> None:
async def test_scan_and_dispatch_calls_dispatch_fn_with_runtime_config() -> None:
now = datetime(2026, 3, 19, 12, 0, tzinfo=timezone.utc)
owner_id = uuid4()
job_id = uuid4()
repo = _FakeRepository(
jobs=[
DueAutomationJob(
id=job_id,
owner_id=owner_id,
schedule_type=ScheduleType.DAILY,
timezone="UTC",
next_run_at=now - timedelta(minutes=1),
)
]
)
queue = _FakeQueue()
service = AutomationSchedulerService(repository=repo, queue=queue)
repo = _FakeRepository(jobs=[_make_orm_job(job_id=job_id, owner_id=owner_id)])
dispatched_calls: list[dict] = []
result = await service.scan_and_dispatch(now_utc=now, limit=10)
async def dispatch_fn(**kwargs: object) -> None:
dispatched_calls.append(kwargs)
service = AutomationJobsService(repository=repo, session=_FakeSession())
result = await service.scan_and_dispatch(
now_utc=now, limit=10, dispatch_fn=dispatch_fn
)
assert result.scanned == 1
assert result.dispatched == 1
assert len(queue.commands) == 1
run_input = queue.commands[0]["run_input"]
assert isinstance(run_input, dict)
assert run_input["forwardedProps"] == {"agent_type": "memory"}
assert queue.commands[0]["automation_job_id"] == str(job_id)
assert repo.commits == 1
assert len(dispatched_calls) == 1
assert dispatched_calls[0]["owner_id"] == owner_id
assert dispatched_calls[0]["runtime_config"] is not None
cfg: RuntimeConfig = dispatched_calls[0]["runtime_config"]
assert len(cfg.enabled_tools) == 2
def test_compute_next_run_at_daily() -> None: