# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 自然语言使用中文。 ## 项目概述 这是一个基于 Laravel 12 + Octane + Docker 的 Agent Runtime Server (ARS),用于提供可部署的 Agent 运行时服务。核心特性包括: - 兼容多种 Agent 模型 - Web 终端实时交互,支持断线重连 - 后台任务持续执行,重连后可续传会话 ## 技术栈 - **PHP**: 8.2+ - **Laravel Framework**: 12.x - **Laravel Octane**: 2.x (FrankenPHP) - **Laravel Horizon**: 5.x (队列监控) - **Laravel Telescope**: 5.x (调试工具) - **数据库**: PostgreSQL 16 - **缓存/队列**: Redis 7 - **认证**: JWT (php-open-source-saver/jwt-auth) - **容器化**: Docker Compose ## 核心架构 ### 数据模型 #### ChatSession (会话) - `session_id` (UUID, 主键): 会话唯一标识 - `session_name`: 会话名称 - `status`: 会话状态 (OPEN/LOCKED/CLOSED) - `last_seq`: 最后消息序号 - `last_message_id`: 最后消息ID #### Message (消息) - `message_id` (UUID, 主键): 消息唯一标识 - `session_id`: 所属会话ID - `role`: 消息角色 (USER/AGENT/TOOL/SYSTEM) - `type`: 消息类型 (user.prompt/agent.message/run.status等) - `content`: 消息内容 (text) - `payload`: 附加数据 (jsonb) - `seq`: 会话内序号 (单调递增) - `reply_to`: 回复的消息ID - `dedupe_key`: 幂等去重键 - **约束**: `unique(session_id, seq)` 和 `unique(session_id, dedupe_key)` ### 会话状态与门禁规则 - **OPEN**: 正常追加所有消息 - **LOCKED**: 拒绝 `role=USER && type=user.prompt` - **CLOSED**: 拒绝追加,例外允许 `role=SYSTEM && type in [run.status, error]` - **状态变更规则**: CLOSED 状态的会话不能重新打开 ### Agent Run 执行流程 1. 用户发送 `user.prompt` 消息后自动触发,或通过 API 手动触发 2. `RunDispatcher` 检查幂等性(基于 `trigger_message_id`) 3. 检查会话是否已有 RUNNING 状态的 run(单会话单任务限制) 4. 创建 `run.status=RUNNING` 消息并派发 `AgentRunJob` 5. `RunLoop` 执行 Agent 调用流程: - `ContextBuilder` 构建上下文 - `AgentProviderInterface` 调用 Agent(当前为 DummyAgentProvider) - `CancelChecker` 检查取消信号 - `OutputSink` 写入 agent.message 6. 完成后写入 `run.status=DONE/FAILED/CANCELED` ### 实时消息推送 (SSE) - **端点**: `GET /api/sessions/{id}/sse?after_seq=123` - **机制**: 1. 先从数据库补发历史消息(seq > after_seq) 2. 订阅 Redis 频道 `session:{id}:messages` 监听新消息 3. 支持 `Last-Event-ID` 自动续传 - **事件格式**: SSE event id 为消息 seq ### 服务层架构 - **ChatService**: 会话和消息的核心业务逻辑 - 使用行锁 (`lockForUpdate`) + 事务保证消息 seq 单调递增 - 通过 `dedupe_key` 实现幂等性 - 消息追加后发布 Redis 事件用于 SSE 推送 - **RunDispatcher**: Agent Run 调度器 - 检查 trigger_message_id 幂等性 - 确保同会话只有一个 RUNNING 状态的 run - **RunLoop**: Agent 执行循环 - 协调 ContextBuilder、AgentProvider、OutputSink、CancelChecker - **OutputSink**: 统一的消息写入接口 - `appendAgentMessage()`: 写入 agent 回复 - `appendRunStatus()`: 写入 run 状态 - `appendError()`: 写入错误信息 ## 常用开发命令 ### Docker 容器操作 ```bash # 构建并启动所有服务 docker compose build docker compose up -d app horizon pgsql redis # 停止服务 docker compose stop # 查看日志 docker compose logs -f app docker compose logs -f horizon # 进入容器 shell docker compose exec app bash ``` ### 数据库操作 ```bash # 运行迁移 docker compose exec app php artisan migrate # 回滚迁移 docker compose exec app php artisan migrate:rollback # 刷新数据库(危险:删除所有表并重新迁移) docker compose exec app php artisan migrate:fresh # 运行 seeder docker compose exec app php artisan db:seed ``` ### 测试 ```bash # 运行所有测试 docker compose exec app php artisan test # 运行特定测试套件 docker compose exec app php artisan test --testsuite=Feature docker compose exec app php artisan test --testsuite=Unit # 运行特定测试文件 docker compose exec app php artisan test tests/Feature/ChatSessionTest.php # 运行特定测试方法(使用 filter) docker compose exec app php artisan test --filter=testCreateSession docker compose exec app php artisan test --filter=testAppendMessageWithDedupe # 显示测试覆盖率 docker compose exec app php artisan test --coverage ``` ### 代码质量 ```bash # 运行 Laravel Pint 格式化代码 docker compose exec app vendor/bin/pint # 只检查格式问题(不修改) docker compose exec app vendor/bin/pint --test # 格式化脏文件(git 变更的文件) docker compose exec app vendor/bin/pint --dirty ``` ### 队列与任务 ```bash # 查看 Horizon 仪表板 # 访问 http://localhost:8000/horizon # 手动运行队列 worker(开发调试用) docker compose exec app php artisan queue:work # 查看失败的任务 docker compose exec app php artisan queue:failed # 重试失败的任务 docker compose exec app php artisan queue:retry all ``` ### 开发调试 ```bash # 启动 Tinker REPL docker compose exec app php artisan tinker # 查看路由列表 docker compose exec app php artisan route:list # 清除缓存 docker compose exec app php artisan cache:clear docker compose exec app php artisan config:clear docker compose exec app php artisan route:clear # 查看实时日志(使用 Laravel Pail) docker compose exec app php artisan pail ``` ### Artisan 生成器 ```bash # 生成 Model(推荐带选项一次性生成相关文件) docker compose exec app php artisan make:model ChatSession -mfs # -m: migration, -f: factory, -s: seeder # 生成 Controller docker compose exec app php artisan make:controller ChatSessionController # 生成 Form Request(用于验证) docker compose exec app php artisan make:request AppendMessageRequest # 生成 Resource(API 响应格式化) docker compose exec app php artisan make:resource ChatSessionResource # 生成 Job docker compose exec app php artisan make:job AgentRunJob # 生成 Service 类 docker compose exec app php artisan make:class Services/ChatService # 生成测试 docker compose exec app php artisan make:test ChatSessionTest --phpunit docker compose exec app php artisan make:test ChatServiceTest --unit --phpunit ``` ## API 路由结构 所有 API 路由均在 `/api/*` 下,除登录和健康检查外均需 JWT 认证: - `POST /api/login`: 用户登录 - `GET /api/health`: 健康检查 - `GET /api/me`: 获取当前用户信息 ### 用户管理 - `GET /api/users`: 用户列表 - `POST /api/users`: 创建用户 - `PUT /api/users/{user}`: 更新用户 - `POST /api/users/{user}/deactivate`: 停用用户 - `POST /api/users/{user}/activate`: 激活用户 ### 会话管理 - `POST /api/sessions`: 创建会话 - `GET /api/sessions`: 会话列表(支持分页、状态过滤、关键词搜索) - `GET /api/sessions/{session_id}`: 获取会话详情 - `PATCH /api/sessions/{session_id}`: 更新会话(重命名、状态变更) - `POST /api/sessions/{session_id}/archive`: 归档会话(幂等,设为 CLOSED) ### 消息管理 - `POST /api/sessions/{session_id}/messages`: 追加消息(支持幂等 dedupe_key) - `GET /api/sessions/{session_id}/messages`: 获取消息列表(支持 after_seq 增量拉取) - `GET /api/sessions/{session_id}/messages/{message_id}`: 获取单条消息 ### 实时与 Agent Run - `GET /api/sessions/{session_id}/sse`: SSE 实时消息流 - `POST /api/sessions/{session_id}/runs`: 手动触发 Agent Run ## 开发注意事项 ### Laravel 12 新特性 - 无 `app/Console/Kernel.php` 和 `app/Http/Kernel.php` - 中间件、路由、异常处理在 `bootstrap/app.php` 配置 - 服务提供者在 `bootstrap/providers.php` 注册 - Commands 自动注册(无需手动注册) ### 数据库操作规范 - 消息追加必须使用 `ChatService::appendMessage()`,不要直接操作 Message 模型 - 会话状态变更必须通过 `ChatService::updateSession()` - 所有涉及 seq 递增的操作必须在事务 + 行锁中完成 ### 测试规范 - 所有测试使用 PHPUnit(非 Pest) - Feature 测试必须测试完整的 HTTP 请求流程 - 测试中使用 Factory 创建模型数据 - 修改代码后必须运行相关测试确保通过 ### 队列配置 - 开发环境可使用同步队列:`.env` 中设置 `QUEUE_CONNECTION=sync` - 生产环境使用 Redis 队列 + Horizon 监控 - `AgentRunJob` 在队列中异步执行 ### 幂等性设计 - 所有可能重复调用的操作都使用 `dedupe_key` - `RunDispatcher` 通过 `trigger_message_id` 确保不会为同一 prompt 重复创建 run - SSE 通过 `Last-Event-ID` / `after_seq` 支持断线续传 ## 环境变量关键配置 ```bash # Octane 服务器 OCTANE_SERVER=frankenphp # 数据库(PostgreSQL) DB_CONNECTION=pgsql DB_HOST=pgsql DB_PORT=5432 DB_DATABASE=ars_backend # Redis REDIS_HOST=redis REDIS_PORT=6379 # 队列 QUEUE_CONNECTION=redis # 或 sync(开发用) # JWT 认证 JWT_SECRET=<生成的密钥> AUTH_GUARD=api # CORS CORS_ALLOWED_ORIGINS=http://localhost:5173 ``` ## 相关文档 - API 详细文档:`docs/ChatSession/chat-session-api.md` - OpenAPI 规范:`docs/ChatSession/chat-session-openapi.yaml` - 用户管理文档:`docs/User/user-api.md`