diff --git a/.mcp.json b/.mcp.json index a36b3bf..74f538e 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,9 +1,12 @@ { "mcpServers": { "laravel-boost": { - "command": "docker compose run app", + "command": "docker", "args": [ - "vendor/bin/sail", + "compose", + "exec", + "app", + "php", "artisan", "boost:mcp" ] diff --git a/CLAUDE.md b/CLAUDE.md index 41905cf..791f6bf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,228 +1,317 @@ - -=== foundation rules === +# 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 状态的会话不能重新打开 -# Laravel Boost Guidelines +### Agent Run 执行流程 -The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications. +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` -## Foundational Context -This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions. +### 实时消息推送 (SSE) -- php - 8.3.28 -- laravel/framework (LARAVEL) - v12 -- laravel/horizon (HORIZON) - v5 -- laravel/octane (OCTANE) - v2 -- laravel/prompts (PROMPTS) - v0 -- laravel/telescope (TELESCOPE) - v5 -- laravel/mcp (MCP) - v0 -- laravel/pint (PINT) - v1 -- laravel/sail (SAIL) - v1 -- phpunit/phpunit (PHPUNIT) - v11 +- **端点**: `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 -## Conventions -- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming. -- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`. -- Check for existing components to reuse before writing a new one. +### 服务层架构 -## Verification Scripts -- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important. +- **ChatService**: 会话和消息的核心业务逻辑 + - 使用行锁 (`lockForUpdate`) + 事务保证消息 seq 单调递增 + - 通过 `dedupe_key` 实现幂等性 + - 消息追加后发布 Redis 事件用于 SSE 推送 -## Application Structure & Architecture -- Stick to existing directory structure - don't create new base folders without approval. -- Do not change the application's dependencies without approval. +- **RunDispatcher**: Agent Run 调度器 + - 检查 trigger_message_id 幂等性 + - 确保同会话只有一个 RUNNING 状态的 run -## Frontend Bundling -- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `vendor/bin/sail npm run build`, `vendor/bin/sail npm run dev`, or `vendor/bin/sail composer run dev`. Ask them. +- **RunLoop**: Agent 执行循环 + - 协调 ContextBuilder、AgentProvider、OutputSink、CancelChecker -## Replies -- Be concise in your explanations - focus on what's important rather than explaining obvious details. +- **OutputSink**: 统一的消息写入接口 + - `appendAgentMessage()`: 写入 agent 回复 + - `appendRunStatus()`: 写入 run 状态 + - `appendError()`: 写入错误信息 -## Documentation Files -- You must only create documentation files if explicitly requested by the user. +## 常用开发命令 +### Docker 容器操作 -=== boost rules === +```bash +# 构建并启动所有服务 +docker compose build +docker compose up -d app horizon pgsql redis -## Laravel Boost -- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them. +# 停止服务 +docker compose stop -## Artisan -- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters. +# 查看日志 +docker compose logs -f app +docker compose logs -f horizon -## URLs -- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port. +# 进入容器 shell +docker compose exec app bash +``` -## Tinker / Debugging -- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly. -- Use the `database-query` tool when you only need to read from the database. +### 数据库操作 -## Reading Browser Logs With the `browser-logs` Tool -- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost. -- Only recent browser logs will be useful - ignore old logs. +```bash +# 运行迁移 +docker compose exec app php artisan migrate -## Searching Documentation (Critically Important) -- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages. -- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc. -- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches. -- Search the documentation before making code changes to ensure we are taking the correct approach. -- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`. -- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`. +# 回滚迁移 +docker compose exec app php artisan migrate:rollback -### Available Search Syntax -- You can and should pass multiple queries at once. The most relevant results will be returned first. +# 刷新数据库(危险:删除所有表并重新迁移) +docker compose exec app php artisan migrate:fresh -1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth' -2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit" -3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order -4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit" -5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms +# 运行 seeder +docker compose exec app php artisan db:seed +``` +### 测试 -=== php rules === +```bash +# 运行所有测试 +docker compose exec app php artisan test -## PHP +# 运行特定测试套件 +docker compose exec app php artisan test --testsuite=Feature +docker compose exec app php artisan test --testsuite=Unit -- Always use curly braces for control structures, even if it has one line. +# 运行特定测试文件 +docker compose exec app php artisan test tests/Feature/ChatSessionTest.php -### Constructors -- Use PHP 8 constructor property promotion in `__construct()`. - - public function __construct(public GitHub $github) { } -- Do not allow empty `__construct()` methods with zero parameters. +# 运行特定测试方法(使用 filter) +docker compose exec app php artisan test --filter=testCreateSession +docker compose exec app php artisan test --filter=testAppendMessageWithDedupe -### Type Declarations -- Always use explicit return type declarations for methods and functions. -- Use appropriate PHP type hints for method parameters. +# 显示测试覆盖率 +docker compose exec app php artisan test --coverage +``` - -protected function isAccessible(User $user, ?string $path = null): bool -{ - ... -} - +### 代码质量 -## Comments -- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on. +```bash +# 运行 Laravel Pint 格式化代码 +docker compose exec app vendor/bin/pint -## PHPDoc Blocks -- Add useful array shape type definitions for arrays when appropriate. +# 只检查格式问题(不修改) +docker compose exec app vendor/bin/pint --test -## Enums -- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`. +# 格式化脏文件(git 变更的文件) +docker compose exec app vendor/bin/pint --dirty +``` +### 队列与任务 -=== sail rules === +```bash +# 查看 Horizon 仪表板 +# 访问 http://localhost:8000/horizon -## Laravel Sail +# 手动运行队列 worker(开发调试用) +docker compose exec app php artisan queue:work -- This project runs inside Laravel Sail's Docker containers. You MUST execute all commands through Sail. -- Start services using `vendor/bin/sail up -d` and stop them with `vendor/bin/sail stop`. -- Open the application in the browser by running `vendor/bin/sail open`. -- Always prefix PHP, Artisan, Composer, and Node commands** with `vendor/bin/sail`. Examples: -- Run Artisan Commands: `vendor/bin/sail artisan migrate` -- Install Composer packages: `vendor/bin/sail composer install` -- Execute node commands: `vendor/bin/sail npm run dev` -- Execute PHP scripts: `vendor/bin/sail php [script]` -- View all available Sail commands by running `vendor/bin/sail` without arguments. +# 查看失败的任务 +docker compose exec app php artisan queue:failed +# 重试失败的任务 +docker compose exec app php artisan queue:retry all +``` -=== tests rules === +### 开发调试 -## Test Enforcement +```bash +# 启动 Tinker REPL +docker compose exec app php artisan tinker -- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass. -- Run the minimum number of tests needed to ensure code quality and speed. Use `vendor/bin/sail artisan test` with a specific filename or filter. +# 查看路由列表 +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/core rules === +# 查看实时日志(使用 Laravel Pail) +docker compose exec app php artisan pail +``` -## Do Things the Laravel Way +### Artisan 生成器 -- Use `vendor/bin/sail artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool. -- If you're creating a generic PHP class, use `vendor/bin/sail artisan make:class`. -- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior. +```bash +# 生成 Model(推荐带选项一次性生成相关文件) +docker compose exec app php artisan make:model ChatSession -mfs +# -m: migration, -f: factory, -s: seeder -### Database -- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins. -- Use Eloquent models and relationships before suggesting raw database queries -- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them. -- Generate code that prevents N+1 query problems by using eager loading. -- Use Laravel's query builder for very complex database operations. +# 生成 Controller +docker compose exec app php artisan make:controller ChatSessionController -### Model Creation -- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `vendor/bin/sail artisan make:model`. +# 生成 Form Request(用于验证) +docker compose exec app php artisan make:request AppendMessageRequest -### APIs & Eloquent Resources -- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention. +# 生成 Resource(API 响应格式化) +docker compose exec app php artisan make:resource ChatSessionResource -### Controllers & Validation -- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages. -- Check sibling Form Requests to see if the application uses array or string based validation rules. +# 生成 Job +docker compose exec app php artisan make:job AgentRunJob -### Queues -- Use queued jobs for time-consuming operations with the `ShouldQueue` interface. +# 生成 Service 类 +docker compose exec app php artisan make:class Services/ChatService -### Authentication & Authorization -- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.). +# 生成测试 +docker compose exec app php artisan make:test ChatSessionTest --phpunit +docker compose exec app php artisan make:test ChatServiceTest --unit --phpunit +``` -### URL Generation -- When generating links to other pages, prefer named routes and the `route()` function. +## API 路由结构 -### Configuration -- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`. +所有 API 路由均在 `/api/*` 下,除登录和健康检查外均需 JWT 认证: -### Testing -- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model. -- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`. -- When creating tests, make use of `vendor/bin/sail artisan make:test [options] {name}` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests. +- `POST /api/login`: 用户登录 +- `GET /api/health`: 健康检查 +- `GET /api/me`: 获取当前用户信息 -### Vite Error -- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `vendor/bin/sail npm run build` or ask the user to run `vendor/bin/sail npm run dev` or `vendor/bin/sail composer run dev`. +### 用户管理 +- `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) -=== laravel/v12 rules === +### 消息管理 +- `POST /api/sessions/{session_id}/messages`: 追加消息(支持幂等 dedupe_key) +- `GET /api/sessions/{session_id}/messages`: 获取消息列表(支持 after_seq 增量拉取) +- `GET /api/sessions/{session_id}/messages/{message_id}`: 获取单条消息 -## Laravel 12 +### 实时与 Agent Run +- `GET /api/sessions/{session_id}/sse`: SSE 实时消息流 +- `POST /api/sessions/{session_id}/runs`: 手动触发 Agent Run -- Use the `search-docs` tool to get version specific documentation. -- Since Laravel 11, Laravel has a new streamlined file structure which this project uses. +## 开发注意事项 -### Laravel 12 Structure -- No middleware files in `app/Http/Middleware/`. -- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files. -- `bootstrap/providers.php` contains application specific service providers. -- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration. -- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration. +### Laravel 12 新特性 +- 无 `app/Console/Kernel.php` 和 `app/Http/Kernel.php` +- 中间件、路由、异常处理在 `bootstrap/app.php` 配置 +- 服务提供者在 `bootstrap/providers.php` 注册 +- Commands 自动注册(无需手动注册) -### Database -- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost. -- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`. +### 数据库操作规范 +- 消息追加必须使用 `ChatService::appendMessage()`,不要直接操作 Message 模型 +- 会话状态变更必须通过 `ChatService::updateSession()` +- 所有涉及 seq 递增的操作必须在事务 + 行锁中完成 -### Models -- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models. +### 测试规范 +- 所有测试使用 PHPUnit(非 Pest) +- Feature 测试必须测试完整的 HTTP 请求流程 +- 测试中使用 Factory 创建模型数据 +- 修改代码后必须运行相关测试确保通过 +### 队列配置 +- 开发环境可使用同步队列:`.env` 中设置 `QUEUE_CONNECTION=sync` +- 生产环境使用 Redis 队列 + Horizon 监控 +- `AgentRunJob` 在队列中异步执行 -=== pint/core rules === +### 幂等性设计 +- 所有可能重复调用的操作都使用 `dedupe_key` +- `RunDispatcher` 通过 `trigger_message_id` 确保不会为同一 prompt 重复创建 run +- SSE 通过 `Last-Event-ID` / `after_seq` 支持断线续传 -## Laravel Pint Code Formatter +## 环境变量关键配置 -- You must run `vendor/bin/sail bin pint --dirty` before finalizing changes to ensure your code matches the project's expected style. -- Do not run `vendor/bin/sail bin pint --test`, simply run `vendor/bin/sail bin pint` to fix any formatting issues. +```bash +# Octane 服务器 +OCTANE_SERVER=frankenphp +# 数据库(PostgreSQL) +DB_CONNECTION=pgsql +DB_HOST=pgsql +DB_PORT=5432 +DB_DATABASE=ars_backend -=== phpunit/core rules === +# Redis +REDIS_HOST=redis +REDIS_PORT=6379 + +# 队列 +QUEUE_CONNECTION=redis # 或 sync(开发用) -## PHPUnit Core +# JWT 认证 +JWT_SECRET=<生成的密钥> +AUTH_GUARD=api -- This application uses PHPUnit for testing. All tests must be written as PHPUnit classes. Use `vendor/bin/sail artisan make:test --phpunit {name}` to create a new test. -- If you see a test using "Pest", convert it to PHPUnit. -- Every time a test has been updated, run that singular test. -- When the tests relating to your feature are passing, ask the user if they would like to also run the entire test suite to make sure everything is still passing. -- Tests should test all of the happy paths, failure paths, and weird paths. -- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files, these are core to the application. - -### Running Tests -- Run the minimal number of tests, using an appropriate filter, before finalizing. -- To run all tests: `vendor/bin/sail artisan test`. -- To run all tests in a file: `vendor/bin/sail artisan test tests/Feature/ExampleTest.php`. -- To filter on a particular test name: `vendor/bin/sail artisan test --filter=testName` (recommended after making a change to a related file). - +# 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` diff --git a/compose.yaml b/backup.yaml similarity index 100% rename from compose.yaml rename to backup.yaml diff --git a/docker-compose-backup.yml b/docker-compose.yml similarity index 100% rename from docker-compose-backup.yml rename to docker-compose.yml diff --git a/docker/app/Dockerfile b/docker/app/Dockerfile index 46caf60..cce4fff 100644 --- a/docker/app/Dockerfile +++ b/docker/app/Dockerfile @@ -1,23 +1,33 @@ -FROM dunglas/frankenphp:1-php8.2 +FROM php:8.4.15-cli-alpine3.23 WORKDIR /app # System packages and PHP extensions required by Laravel/Octane -RUN apt-get update \ - && apt-get install -y --no-install-recommends \ +RUN apk update \ + && apk add --no-cache \ git \ unzip \ libzip-dev \ - libpq-dev \ - zlib1g-dev \ + postgresql-dev \ + zlib-dev \ + libpq \ + icu-dev \ + gcc \ + g++ \ + make \ + autoconf \ + libc-dev \ + pkgconfig \ && docker-php-ext-install \ pcntl \ zip \ pdo_mysql \ pdo_pgsql \ + intl \ && pecl install redis \ && docker-php-ext-enable redis \ - && rm -rf /var/lib/apt/lists/* + pdo_pgsql \ + && rm -rf /var/cache/apk/* # Composer for dependency management COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer diff --git a/phpunit.xml b/phpunit.xml index bbfcf81..356a8fa 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -30,5 +30,6 @@ +