# 贡献指南

感谢你对 OpenViking 感兴趣！我们欢迎各种形式的贡献：

- 报告 Bug
- 提交功能请求
- 改进文档
- 贡献代码

---

## 开发环境设置

### 前置要求

- **Python**: 3.10+
- **Go**: 1.22+ (从源码构建 AGFS 组件需要)
- **Rust**: 1.88+（从源码构建需要；打包流程会同时构建内置 `ov` CLI）
- **C++ 编译器**: GCC 9+ 或 Clang 11+ (构建核心扩展需要，必须支持 C++17)
- **CMake**: 3.12+

#### 平台相关的本地构建工具

- **Linux**: 建议安装 `build-essential`；某些环境下还可能需要 `pkg-config`
- **macOS**: 安装 Xcode Command Line Tools（`xcode-select --install`）
- **Windows**: 本地原生构建建议安装 CMake 和 MinGW

#### 支持的平台 (预编译 Wheel 包)

OpenViking 为以下环境提供预编译的 **Wheel** 包，安装时无需本地编译：

- **Windows**: x86_64
- **macOS**: x86_64, arm64 (Apple Silicon)
- **Linux**: x86_64, arm64 (manylinux)

对于其他平台（如 FreeBSD 等），安装时 `pip` 将会自动从源码进行编译。请确保已安装上述[前置要求](#前置要求)中的工具。

### 1. Fork 并克隆

```bash
git clone https://github.com/YOUR_USERNAME/openviking.git
cd openviking
```

### 2. 安装依赖

我们推荐使用 `uv` 进行 Python 环境管理：

```bash
# 安装 uv (如果尚未安装)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 同步依赖并创建虚拟环境
uv sync --all-extras
source .venv/bin/activate  # Linux/macOS
# 或者 .venv\Scripts\activate  # Windows
```

#### 本地开发与原生组件重建

OpenViking 默认使用 `binding-client` 模式，这依赖预先构建的原生产物。如果你修改了 **AGFS (Go)** 代码、内置的 **Rust CLI**，或 **C++ 扩展**，或者这些预编译产物未找到，你需要重新编译并安装它们，以使更改在本地环境中生效。在项目根目录下运行以下命令：

```bash
uv pip install -e . --force-reinstall
```

该命令会强制重新执行 `setup.py`，触发 AGFS、内置 `ov` CLI 和 C++ 组件的重新编译与安装。

### 3. 配置环境

创建配置文件 `~/.openviking/ov.conf`：

```json
{
  "embedding": {
    "dense": {
      "provider": "volcengine",
      "api_key": "your-api-key",
      "model": "doubao-embedding-vision-250615",
      "api_base": "https://ark.cn-beijing.volces.com/api/v3",
      "dimension": 1024,
      "input": "multimodal"
    }
  },
  "vlm": {
    "api_key": "your-api-key",
    "model": "doubao-seed-2-0-pro-260215",
    "api_base": "https://ark.cn-beijing.volces.com/api/v3"
  }
}
```

设置环境变量：

```bash
export OPENVIKING_CONFIG_FILE=~/.openviking/ov.conf
```

### 4. 验证安装

```python
import asyncio
import openviking as ov

async def main():
    client = ov.AsyncOpenViking(path="./test_data")
    await client.initialize()
    print("OpenViking initialized successfully!")
    await client.close()

asyncio.run(main())
```

### 5. 构建 Rust CLI（可选）

Rust CLI (`ov`) 提供高性能的命令行客户端，用于连接 OpenViking Server 进行操作。

即使你不打算直接使用 `ov`，只要走 OpenViking 的源码构建流程，Rust 工具链仍然是必需的，因为打包过程也会构建内置 CLI 二进制。

```bash
# 从源码编译安装
cargo install --path crates/ov_cli

# 或者使用一键安装脚本（下载预编译二进制）
curl -fsSL https://raw.githubusercontent.com/volcengine/OpenViking/main/crates/ov_cli/install.sh | bash
```

安装后通过 `ov --help` 查看所有可用命令。CLI 连接配置见 `~/.openviking/ovcli.conf`。

---

## 项目结构

```
openviking/
├── pyproject.toml        # 项目配置
├── Cargo.toml            # Rust workspace 配置
├── third_party/          # 第三方依赖
│   └── agfs/             # AGFS 文件系统
│
├── openviking/           # Python SDK
│   ├── async_client.py   # AsyncOpenViking 客户端
│   ├── sync_client.py    # SyncOpenViking 客户端
│   ├── client/           # 本地与 HTTP 客户端实现
│   ├── console/          # 独立 console UI 与代理服务
│   ├── core/             # 核心数据模型与目录抽象
│   ├── message/          # 会话消息与 part 模型
│   ├── models/           # Embedding 与 VLM 后端
│   ├── parse/            # 资源解析器与检测器
│   ├── resource/         # 资源处理与 watch 管理
│   ├── retrieve/         # 检索系统
│   ├── server/           # HTTP 服务端
│   ├── service/          # 共享 service 层
│   ├── session/          # 会话管理与压缩
│   ├── storage/          # 存储层
│   ├── telemetry/        # 操作级 telemetry
│   ├── trace/            # trace 与运行时跟踪辅助
│   ├── utils/            # 工具类与配置辅助
│   └── prompts/          # 提示词模板
│
├── crates/               # Rust 组件
│   └── ov_cli/           # Rust CLI 客户端
│       ├── src/          # CLI 源码
│       └── install.sh    # 一键安装脚本
│
├── src/                  # C++ 扩展源码（Python abi3）
│
├── tests/                # 测试套件
│   ├── client/           # 客户端测试
│   ├── console/          # Console 测试
│   ├── core/             # 核心逻辑测试
│   ├── parse/            # 解析器测试
│   ├── resource/         # 资源处理测试
│   ├── retrieve/         # 检索测试
│   ├── server/           # 服务端测试
│   ├── service/          # Service 层测试
│   ├── session/          # 会话测试
│   ├── storage/          # 存储测试
│   ├── telemetry/        # Telemetry 测试
│   ├── vectordb/         # 向量数据库测试
│   └── integration/      # 端到端测试
│
└── docs/                 # 文档
    ├── en/               # 英文文档
    └── zh/               # 中文文档
```

---

## 代码风格

我们使用以下工具来保持代码一致性：

| 工具 | 用途 | 配置 |
|------|---------|--------|
| **Ruff** | Linting, 格式化, 导入排序 | `pyproject.toml` |
| **mypy** | 类型检查 | `pyproject.toml` |

### 自动检查（推荐）

我们使用 [pre-commit](https://pre-commit.com/) 在每次提交前自动运行这些检查。这确保您的代码无需手动努力即可符合标准。

1. **安装 pre-commit**：
   ```bash
   pip install pre-commit
   ```

2. **安装 git hooks**：
   ```bash
   pre-commit install
   ```

现在，当您运行 `git commit` 时，`ruff`（检查和格式化）将自动运行。如果任何检查失败，它可能会自动修复文件。您只需添加更改并再次提交即可。

### 运行检查

```bash
# 格式化代码
ruff format openviking/

# Lint 检查
ruff check openviking/

# 类型检查
mypy openviking/
```

### 风格指南

1. **行宽**：100 字符
2. **缩进**：4 个空格
3. **字符串**：推荐使用双引号
4. **类型提示**：鼓励但不强制
5. **Docstrings**：公共 API 必须包含（最多 1-2 行）

---

## 测试

### 运行测试

```bash
# 运行所有测试
pytest

# 运行特定测试模块
pytest tests/client/ -v
pytest tests/server/ -v
pytest tests/parse/ -v

# 运行特定测试文件
pytest tests/client/test_lifecycle.py

# 运行特定测试
pytest tests/client/test_lifecycle.py::TestClientInitialization::test_initialize_success

# 按关键字运行
pytest -k "search" -v

# 运行并生成覆盖率报告
pytest --cov=openviking --cov-report=term-missing
```

### 编写测试

测试按模块组织在 `tests/` 的子目录中。项目使用 `asyncio_mode = "auto"`，异步测试**不需要** `@pytest.mark.asyncio` 装饰器：

```python
# tests/client/test_example.py
from openviking import AsyncOpenViking


class TestAsyncOpenViking:
    async def test_initialize(self, uninitialized_client: AsyncOpenViking):
        await uninitialized_client.initialize()
        assert uninitialized_client._service is not None
        await uninitialized_client.close()

    async def test_add_resource(self, client: AsyncOpenViking, sample_markdown_file):
        result = await client.add_resource(
            path=str(sample_markdown_file),
            reason="test document"
        )
        assert "root_uri" in result
        assert result["root_uri"].startswith("viking://")
```

常用 fixture 定义在 `tests/conftest.py` 中，包括 `client`（已初始化的 `AsyncOpenViking`）、`uninitialized_client`、`temp_dir`、`sample_markdown_file` 等。

---

## 贡献流程

### 1. 创建分支

```bash
git checkout main
git pull origin main
git checkout -b feature/your-feature-name
```

分支命名规范：
- `feature/xxx` - 新功能
- `fix/xxx` - Bug 修复
- `docs/xxx` - 文档更新
- `refactor/xxx` - 代码重构

### 2. 修改代码

- 遵循代码风格指南
- 为新功能添加测试
- 根据需要更新文档

### 3. 提交更改

```bash
git add .
git commit -m "feat: add new parser for xlsx files"
```

### 4. 推送并创建 PR

```bash
git push origin feature/your-feature-name
```

然后在 GitHub 上创建一个 Pull Request。

---

## 提交规范

我们遵循 [Conventional Commits](https://www.conventionalcommits.org/)：

```
<type>(<scope>): <subject>

<body>

<footer>
```

### 类型

| 类型 | 描述 |
|------|-------------|
| `feat` | 新功能 |
| `fix` | Bug 修复 |
| `docs` | 文档 |
| `style` | 代码风格（不影响逻辑） |
| `refactor` | 代码重构 |
| `perf` | 性能优化 |
| `test` | 测试 |
| `chore` | 构建/工具 |

### 示例

```bash
# 新功能
git commit -m "feat(parser): add support for xlsx files"

# Bug 修复
git commit -m "fix(retrieval): fix score calculation in rerank"

# 文档
git commit -m "docs: update quick start guide"

# 重构
git commit -m "refactor(storage): simplify interface methods"
```

---

## Pull Request 指南

### PR 标题

使用与提交消息相同的格式。

### PR 描述模板

```markdown
## Summary

简要描述更改及其目的。

## Type of Change

- [ ] New feature (feat)
- [ ] Bug fix (fix)
- [ ] Documentation (docs)
- [ ] Refactoring (refactor)
- [ ] Other

## Testing

描述如何测试这些更改：
- [ ] Unit tests pass
- [ ] Manual testing completed

## Related Issues

- Fixes #123
- Related to #456

## Checklist

- [ ] Code follows project style guidelines
- [ ] Tests added for new functionality
- [ ] Documentation updated (if needed)
- [ ] All tests pass
```

---

## CI/CD 工作流

我们使用 **GitHub Actions** 进行持续集成和持续部署。我们的工作流设计为模块化和分层的。

### 1. 自动工作流

| 事件 | 工作流 | 描述 |
|-------|----------|-------------|
| **Pull Request** | `pr.yml` | 运行 **Lint** (Ruff, Mypy) 和 **Test Lite** (Linux + Python 3.10 上的集成测试)。为贡献者提供快速反馈。(显示为 **01. Pull Request Checks**) |
| **Push to Main** | `ci.yml` | 运行 **Test Full** (所有操作系统：Linux/Win/Mac，所有 Py版本：3.10-3.14) 和 **CodeQL** (安全扫描)。确保主分支稳定性。(显示为 **02. Main Branch Checks**) |
| **Release Published** | `release.yml` | 当您在 GitHub 上创建 Release 时触发。自动构建源码包和 wheel 包，基于 Git Tag 确定版本号，并发布到 **PyPI**。(显示为 **03. Release**) |
| **Weekly Cron** | `schedule.yml` | 每周日运行 **CodeQL** 安全扫描。(显示为 **04. Weekly Security Scan**) |

仓库中另外还有用于 PR review 自动化、Docker 镜像构建和 Rust CLI 打包的工作流。

### 2. 手动触发工作流

维护者可以从 "Actions" 选项卡手动触发以下工作流，以执行特定任务或调试问题。

#### A. 代码检查 (`11. _Lint Checks`)
运行代码风格检查 (Ruff) 和类型检查 (Mypy) 。无需参数。

> **提示**：建议在本地安装 [pre-commit](https://pre-commit.com/) 以在提交前自动运行这些检查（详见上文[自动检查](#自动检查推荐)章节）。

#### B. 简易测试 (`12. _Test Suite (Lite)`)
运行快速集成测试，支持自定义矩阵配置。

*   **Inputs**:
    *   `os_json`: 操作系统列表的 JSON 字符串数组 (例如 `["ubuntu-24.04"]`)。
    *   `python_json`: Python 版本列表的 JSON 字符串数组 (例如 `["3.10"]`)。

#### C. 完整测试 (`13. _Test Suite (Full)`)
在所有支持的平台 (Linux/Mac/Win) 和 Python 版本 (3.10-3.14) 上运行完整的测试套件。手动触发时支持自定义矩阵配置。

*   **Inputs**:
    *   `os_json`: 操作系统列表 (默认: `["ubuntu-24.04", "macos-14", "windows-latest"]`)。
    *   `python_json`: Python 版本列表 (默认: `["3.10", "3.11", "3.12", "3.13", "3.14"]`)。

#### D. 安全扫描 (`14. _CodeQL Scan`)
运行 CodeQL 安全分析。无需参数。

#### E. 构建发行版 (`15. _Build Distribution`)
仅构建 Python wheel 包，不发布。

*   **Inputs**:
    *   `os_json`: 操作系统列表 (默认: `["ubuntu-24.04", "ubuntu-24.04-arm", "macos-14", "macos-15-intel", "windows-latest"]`)。
    *   `python_json`: Python 版本列表 (默认: `["3.10", "3.11", "3.12", "3.13", "3.14"]`)。
    *   `build_sdist`: 是否构建源码包 (默认: `true`)。
    *   `build_wheels`: 是否构建 Wheel 包 (默认: `true`)。

#### F. 发布发行版 (`16. _Publish Distribution`)
将已构建的包（需要提供构建运行 ID）发布到 PyPI。

*   **Inputs**:
    *   `target`: 选择发布目标 (`testpypi`, `pypi`, `both`)。
    *   `build_run_id`: 构建 Workflow 的 Run ID (必需，从构建运行的 URL 中获取)。

#### G. 手动发布 (`03. Release`)
一站式构建并发布（包含构建和发布步骤）。

> **版本号与 Tag 规范**：
> 本项目使用 `setuptools_scm` 自动从 Git Tag 提取版本号。
> *   **Tag 命名规范**：必须遵循 `vX.Y.Z` 格式（例如 `v0.1.0`, `v1.2.3`）。Tag 必须是符合语义化版本规范的。
> *   **Release 构建**：当触发 Release 事件时，版本号直接对应 Git Tag（例如 `v0.1.0` -> `0.1.0`）。
> *   **手动构建/非 Tag 构建**：版本号会包含距离上一个 Tag 的提交次数（例如 `0.1.1.dev3`）。
> *   **确认版本号**：发布任务完成后，您可以在 Workflow 运行详情页的 **Summary** 页面顶部（**Notifications** 区域）直接看到发布的版本号（例如 `Successfully published to PyPI with version: 0.1.8`）。您也可以在日志或 **Artifacts** 产物文件名中确认。

*   **Inputs**:
    *   `target`: 选择发布目标。
        *   `none`: 仅构建工件（不发布）。用于验证构建能力。
        *   `testpypi`: 发布到 TestPyPI。用于 Beta 测试。
        *   `pypi`: 发布到官方 PyPI。
        *   `both`: 发布到两者。
    *   `os_json`: 构建平台 (默认包含所有)。
    *   `python_json`: Python 版本 (默认包含所有)。
    *   `build_sdist`: 是否构建源码包 (默认: `true`)。
    *   `build_wheels`: 是否构建 Wheel 包 (默认: `true`)。

> **发布注意事项**：
> *   **测试优先**：强烈建议在发布到正式 PyPI 之前，先发布到 **TestPyPI** 进行验证。请注意，PyPI 和 TestPyPI 是两个完全独立的环境，账号和包数据互不相通。
> *   **版本不可覆盖**：PyPI 和 TestPyPI 均**不允许覆盖**已发布的同名同版本包。如果您需要重新发布，必须升级版本号（例如打一个新的 Tag 或产生新的 dev 版本）。如果尝试发布已存在的版本，工作流将会失败。

---

## Issue 指南

### Bug 报告

请提供：

1. **环境**
   - Python 版本
   - OpenViking 版本
   - 操作系统

2. **复现步骤**
   - 详细步骤
   - 代码片段

3. **预期与实际行为**

4. **错误日志**（如果有）

### 功能请求

请描述：

1. **问题**：您试图解决什么问题？
2. **解决方案**：您建议什么解决方案？
3. **替代方案**：您是否考虑过其他方法？

---

## 文档

文档采用 Markdown 格式，位于 `docs/` 目录下：

- `docs/en/` - 英文文档
- `docs/zh/` - 中文文档

### 文档指南

1. 代码示例必须可运行
2. 保持文档与代码同步
3. 使用清晰、简洁的语言

---

## 行为准则

参与本项目即表示您同意：

1. **尊重**：保持友好和专业的态度
2. **包容**：欢迎来自不同背景的贡献者
3. **建设性**：提供有帮助的反馈
4. **专注**：保持讨论集中在技术层面

---

## 获取帮助

如果您有问题：

- [GitHub Issues](https://github.com/volcengine/openviking/issues)
- [Discussions](https://github.com/volcengine/openviking/discussions)

---

感谢您的贡献！
