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 @@
+