13 KiB
Agent Platform Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 将 v3.1 Agent 底座和 05 接口规范落成可恢复、可测试、与 HTTP/SSE 解耦的 MVP 实现。
Architecture: API 层只负责 JWT、请求映射和 View;AgentRunApplicationService 负责受理、幂等和 Outbox;Worker 通过 AgentExecutor 调用 AgentFactory/BaseAgent.execute()。MySQL 是运行状态、最终消息和审计权威源,Redis 只做缓存和通知,SSE 从运行查询投影输出结果级恢复流。
Tech Stack: Python 3.11+、FastAPI、Pydantic v2、SQLAlchemy 2、Alembic、MySQL 8、Redis、pytest、pytest-asyncio、httpx;模型、Milvus、Neo4j 通过 Service Protocol/Port 注入。
Spec: docs/05-接口文档.md、docs/01-通用Agent平台开发设计.md、docs/02-数据库建表设计.md、docs/03-平台端到端流程文档.md、AGENTS.md
Global Constraints
- 数据库允许新增表和字段,禁止重命名、删除或改变已有表及已有字段定义。
- MVC+S 固定为 Controller -> Service -> Repository -> Model;Agent 属于 Service 层。
- Agent 必须由
AgentFactory创建并继承BaseAgent,不得绕过公共鉴权、记忆、模型、工具、合规、审计和事件流程。 agent_run是运行主键;trace_id只用于追踪;不得复用trace_id代替run_id。- 最终助手消息、审计、幂等完成状态、
agent_run=succeeded和领域 Outbox 必须在同一事务提交。 - 记忆提取事件必须在
complete_run()同一事务写入 Outbox,请求线程不得提交后直接调用记忆提取。 - BaseAgent 只返回传输无关的
RunProgressEvent;SSE 由 View 适配,MVP 只实现结果级恢复。 - 场内基金模拟交易是当前业务范围;场外运营独立建表、独立接口。
Task 1: 项目骨架与公共契约
Files:
- Create:
pyproject.toml - Create:
app/core/contracts.py - Create:
app/core/errors.py - Create:
app/core/context.py - Create:
tests/unit/core/test_contracts.py - Create:
tests/unit/core/test_errors.py
Interfaces:
-
Produces
AgentRequest,AgentRequestMetadata,RequestContext,AgentDefinition,ResolvedAgentConfig,RunProgressEvent,AgentResult,DomainEventandAgentErrorclasses matching 01 contract IDs. -
Also produces immutable transport-neutral
RunAccepted,RunCancellationandRunViewprojection dataclasses used by the application and View layers. -
Step 1: Write failing validation tests for forbidden metadata keys, blank messages, invalid idempotency keys, confidence outside
0..1, and extra request fields. -
Step 2: Run
python -m pytest tests/unit/core/test_contracts.py -q; expect validation failures before implementation. -
Step 3: Implement Pydantic/dataclass contracts with
ConfigDict(extra="forbid"); keep HTTP DTOs separate from internal contracts. -
Step 4: Add stable error codes and public messages; errors must not contain stack traces or provider responses.
-
Step 5: Run
python -m pytest tests/unit/core -qandpython -m ruff check app tests.
Task 2: 数据库迁移与 Repository
Files:
- Create:
alembic/versions/20260909_agent_platform_v31.py - Create:
app/model/agent_run.py - Create:
app/model/platform_entities.py - Create:
app/repository/agent_run_repository.py - Create:
app/repository/idempotency_repository.py - Create:
app/repository/outbox_repository.py - Create:
tests/integration/repository/test_agent_run_repository.py
Interfaces:
-
AgentRunRepository.create_queued(...) -> AgentRun -
AgentRunRepository.claim(run_id, worker_id, lease_seconds) -> AgentRun | None -
AgentRunRepository.request_cancel(run_id, user_id) -> AgentRun -
IdempotencyRepository.claim(scope, request_hash) -> ClaimResult -
OutboxRepository.append(event: DomainEvent) -> None -
ClaimResultis a typed result withdecision,record_id,existing_run_idandrequest_hash;AgentRunis the SQLAlchemy model foragent_run. -
Step 1: Write migration tests asserting creation of
agent_run, ten platform increment tables, foreign keys, status check, uniquerun_id, uniqueidempotency_id, and lease indexes. -
Step 2: Run
alembic upgrade headagainst an empty MySQL test schema and inspect with SQLAlchemy Inspector. -
Step 3: Implement
agent_runmigration exactly as 02 §8.4; do not alter baseline tables. -
Step 4: Implement repositories with conditional updates for leases, cancellation and terminal states.
-
Step 5: Test duplicate claims, expired lease takeover, concurrent completion and forbidden terminal-state transitions.
-
Step 6: Run
alembic downgrade -1in a disposable schema and verify no baseline table or column changed.
Task 3: JWT、统一信封和 API DTO
Files:
- Create:
app/api/dependencies/auth.py - Create:
app/api/schemas/envelopes.py - Create:
app/api/schemas/agent_runs.py - Create:
app/api/mappers/agent_run_mapper.py - Create:
tests/api/test_auth.py - Create:
tests/api/test_envelopes.py
Interfaces:
-
build_request_context(request) -> RequestContext -
AgentRunCreateRequest -
success_envelope(data, trace_id) -
error_envelope(code, message, trace_id, field_errors) -
Step 1: Test missing token, invalid signature, wrong issuer/audience, expiry and revoked
jtireturn401. -
Step 2: Test roles, customer assignment and data scope are reloaded server-side and cannot be supplied by request body or metadata.
-
Step 3: Implement JWT dependency and trace middleware; always return
X-Trace-ID. -
Step 4: Implement JSON DTO validation, cursor validation, decimal-string serialization and
BIGINTstring serialization. -
Step 5: Run
python -m pytest tests/api -q.
Task 4: Agent 运行受理、幂等和 Outbox
Files:
- Create:
app/service/agent_run_application_service.py - Create:
app/service/run_dispatch_port.py - Create:
app/api/controllers/agent_runs.py - Create:
tests/service/test_agent_run_application_service.py - Create:
tests/api/test_agent_runs_create.py
Interfaces:
-
AgentRunApplicationService.accept(payload, context) -> RunAccepted -
AgentRunApplicationService.request_cancel(run_id, context, idempotency_key) -> RunCancellation -
RunDispatchPort.enqueue(run_id) -> None -
RunAcceptedandRunCancellationare the immutable result dataclasses from Task 1; controllers never return ORM objects. -
Step 1: Write failing transaction tests for user message + idempotency +
agent_run+agent.run_requestedatomicity. -
Step 2: Test same key/same hash returns original run; same key/different hash returns
409 IDEMPOTENCY_CONFLICT. -
Step 3: Implement
accept(); do not execute model or Agent in the HTTP request. -
Step 4: Implement cancellation with
cancel_requestedconditional update andagent.run_cancel_requestedOutbox. -
Step 5: Add controller routes and verify response is
202withrun_id,trace_id,status_url,events_url. -
Step 6: Run
python -m pytest tests/service/test_agent_run_application_service.py tests/api/test_agent_runs_create.py -q.
Task 5: AgentFactory、BaseAgent.execute 与 Worker
Files:
- Create:
app/service/agent/base.py - Create:
app/service/agent/factory.py - Create:
app/service/agent/executor.py - Create:
app/worker/agent_run_worker.py - Create:
tests/contract/test_registered_agents.py - Create:
tests/worker/test_agent_run_worker.py
Interfaces:
-
AgentFactory.create(agent_type, context) -> BaseAgent -
BaseAgent.execute(request, context) -> AsyncIterator[RunProgressEvent] -
AgentExecutor.execute_run(run_id) -> None -
AgentRunWorker.claim_and_execute() -> None -
Step 1: Write contract tests proving every registered Agent subclasses BaseAgent, declares valid definition, and cannot override
executeor public governance methods. -
Step 2: Test Worker lease claim, retry after expiry, same
run_idreuse and cancellation checkpoint. -
Step 3: Implement BaseAgent seven-step flow with injected Services; no HTTP/SSE imports.
-
Step 4: Implement Worker exception translation to
AgentError; retry recoverable failures and terminalize non-recoverable failures. -
Step 5: Run
python -m pytest tests/contract tests/worker -q.
Task 6: complete_run、事务 Outbox 和结果查询
Files:
- Create:
app/service/agent_persistence_service.py - Create:
app/service/run_query_service.py - Create:
app/api/controllers/run_queries.py - Create:
tests/service/test_agent_persistence_service.py - Create:
tests/api/test_run_queries.py
Interfaces:
-
AgentPersistenceService.complete_run(..., memory_extraction_requested: bool) -> int -
RunQueryService.get(run_id, context) -> RunView -
RunViewis the persisted HTTP-neutral projection from Task 1; itsresultis populated only from database rows. -
Step 1: Write a transaction test that fails if assistant message, audit, idempotency completion,
agent_run=succeeded, or Outbox is missing after rollback. -
Step 2: Test
memory.extraction_requestedis present in the same transaction when requested and absent otherwise. -
Step 3: Implement domain event construction with
event_id,aggregate_type,occurred_at, andtrace_id. -
Step 4: Implement result projection from persisted message/run rows; never read Worker memory for GET responses.
-
Step 5: Run
python -m pytest tests/service/test_agent_persistence_service.py tests/api/test_run_queries.py -q.
Task 7: 结果级恢复 SSE 与会话接口
Files:
- Create:
app/view/sse_view.py - Create:
app/api/controllers/run_events.py - Create:
app/api/controllers/conversations.py - Create:
app/api/schemas/conversations.py - Create:
tests/api/test_run_events.py - Create:
tests/api/test_conversations.py
Interfaces:
-
SseView.stream(run_id, context) -> StreamingResponse -
GET /api/v1/agent-runs/{run_id}/events -
POST/GET /api/v1/conversations...routes listed in 05 §7 -
Step 1: Test SSE headers, event order, 15-second comment heartbeat, terminal
done/error, and notools/delta/donebefore persistence success. -
Step 2: Test reconnect after disconnect rebuilds complete result from
agent_runandconversation_message; do not implement event replay. -
Step 3: Implement View adapter from
RunProgressEventto 01 §12 events; BaseAgent remains HTTP-free. -
Step 4: Implement session ownership, message cursor pagination, closure, feedback and public handover request mapping.
-
Step 5: Run
python -m pytest tests/api/test_run_events.py tests/api/test_conversations.py -q.
Task 8: 平台管理面与配置发布
Files:
- Create:
app/api/controllers/admin_config.py - Create:
app/api/controllers/admin_models.py - Create:
app/api/controllers/admin_prompts.py - Create:
app/api/controllers/admin_intents.py - Create:
app/api/controllers/admin_audit.py - Create:
app/service/config_release_service.py - Create:
tests/api/test_admin_config.py
Interfaces:
-
Routes and permissions exactly match 05 §9 and §19 entries A001-A033.
-
ConfigReleaseService.validate/review/activate/rollbackare separate methods with maker-checker enforcement. -
Step 1: Test creator cannot review own release, invalid release cannot activate, and
If-Matchconflict returns409. -
Step 2: Test active template/intent uniqueness and fallback endpoint foreign-key/order validation.
-
Step 3: Implement draft/review/activate/rollback service transactions and audit records.
-
Step 4: Implement route DTOs without exposing secrets, internal URLs or old
fallback_endpoint_ids. -
Step 5: Run
python -m pytest tests/api/test_admin_config.py -q.
Task 9: OpenAPI、契约测试和故障演练
Files:
-
Create:
openapi/agent-platform-v1.yaml -
Create:
tests/contract/test_openapi_contract.py -
Create:
tests/security/test_data_scope.py -
Create:
tests/recovery/test_agent_run_recovery.py -
Modify:
docs/05-接口文档.mdonly when the HTTP contract intentionally changes -
Step 1: Generate OpenAPI from the same DTO/router source and compare paths, methods, required headers and response envelopes with 05 §19.
-
Step 2: Test cross-customer access returns
404, JWT failures return401, and Agent cannot execute write tools. -
Step 3: Test Worker crash, lease takeover, Redis loss, Outbox retry/dead-letter and client disconnect.
-
Step 4: Run
python -m pytest -q,python -m ruff check app tests, andpython -m mypy app. -
Step 5: Run empty-schema migration and upgrade-schema migration in disposable MySQL databases; verify 49-table count and immutable baseline definitions.