W17: extract ai_common shared module + fix anthropic data race + brace bugs

- New plugins_upper/ai_common/ static library: shared PluginConfig, ToolCallAccum,
  StreamContext, secure_zero, extract_host_port, serialize_tool_calls, free_chat_result
- Refactored openai/anthropic plugins to use dstalk_ai:: namespace from ai_common
- Fixed anthropic g_config raw pointer → std::atomic (data race)
- Added SSE parse error counter with threshold abort (kMaxSseParseErrors=5)
- Fixed missing closing brace in both plugins' error-body catch block
- Updated test targets: ai_common include path + link, using namespace dstalk_ai
- plugin_loader_test: added stub_unreg + service_registry.cpp for unregister_service
- Includes pre-existing uncommitted changes from prior waves

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 16:58:25 +08:00
parent ba7382db2a
commit 8faa02c3d5
49 changed files with 1062 additions and 413 deletions

View File

@@ -90,7 +90,7 @@ struct dstalk_ai_service_t {
每种服务都有一个预定义的 vtable 结构体(定义在 `dstalk_services.h`)。第三方也可以扩展自己的服务 vtable版本号随注册一起提供允许消费者做最低版本检查。
服务注册采用 **name + version** 两要素:
- 全局唯一名称(如 `"ai.openai"``"http"``"file_io"`)。
- 全局唯一名称(如 `"ai_openai"``"http"``"file_io"`)。
- 版本号(消费者可以要求 `min_version`)。
---

View File

@@ -87,7 +87,7 @@ Host 收到非零返回值后,会跳过后续插件的初始化并报告警告
**契约 3register_service 注册自己的服务。** 插件将自己的 vtable 注册到服务注册表后,其他依赖它的插件才能在后续的 `on_init` 中通过 `query_service` 找到它。
```c
return host->register_service("ai.openai", 1, &g_service);
return host->register_service("ai_openai", 1, &g_service);
```
注册表内的 vtable 是原始指针,不拷贝。因此 vtable 指向的结构体必须是**静态生命周期**(全局变量或 static 局部变量)。

View File

@@ -110,7 +110,7 @@ Linux/macOS 通常共享 libc但静态链接或不同 libc 版本时同样可
### 4.2 重复注册
同一 `name` 不可重复注册:第二次调用返回 `-2``service_registry.cpp:13`)。插件应检查返回
值,在共享服务名(如 `"ai.openai"`)的场景中避免冲突。
值,在共享服务名(如 `"ai_openai"`)的场景中避免冲突。
### 4.3 版本协商

View File

@@ -6,35 +6,65 @@
## 1. 安装工具链
dstalk 需要 CMake、Ninja、LLVM/Clang 和 Conan2。`setup.bat` 全自动下载安装到 `tools/` 目录
dstalk 需要 CMake、Ninja、LLVM/Clang 和 Conan2。`tools/` 下的脚本全自动安装
**Windows:**
```bash
cd tools
setup.bat
```
**Mac:**
```bash
# 方式 A: 手动安装后运行脚本
brew install cmake ninja
cd tools && bash setup.sh
# 方式 B: 脚本全自动 (推荐)
cd tools && bash setup.sh
```
**Linux (Ubuntu/Debian):**
```bash
# 方式 A: 手动安装后运行脚本
sudo apt install cmake ninja-build
cd tools && bash setup.sh
# 方式 B: 脚本全自动 (推荐)
cd tools && bash setup.sh
```
> **前提**: 系统需已安装 Python 3.10+。
>
> 网络不畅时, 可手动下载放入对应目录:
> - [Ninja](https://github.com/ninja-build/ninja/releases) → `tools/ninja/ninja.exe`
> - [CMake](https://cmake.org/download/) → `tools/cmake/bin/cmake.exe`
> - [LLVM](https://github.com/llvm/llvm-project/releases) → `tools/llvm/bin/clang.exe`
> - Conan2 通过 pip 安装到 `tools/.venv/Scripts/conan.exe`
> - [Ninja](https://github.com/ninja-build/ninja/releases) → `tools/ninja/ninja` (或 `ninja.exe`)
> - [CMake](https://cmake.org/download/) → `tools/cmake/bin/cmake` (或 `cmake.exe`)
> - [LLVM](https://github.com/llvm/llvm-project/releases) → `tools/llvm/bin/clang` (或 `clang.exe`)
> - Conan2 通过 pip 安装到 `tools/.venv/Scripts/conan.exe` (Win) 或 `tools/.venv/bin/conan` (Mac/Linux)
---
## 2. 编译
项目根目录提供 `build.bat`, 一键完成: Conan 拉取依赖 -> CMake 配置 -> Ninja 编译。
项目根目录提供 `build.bat` (Windows) / `build.sh` (Mac/Linux), 一键完成: Conan 拉取依赖 -> CMake 配置 -> Ninja 编译。
**Windows:**
```bash
build.bat
```
编译产物输出到 `build/` 目录。核心产物:
- `build/dstalk_core/dstalk.dll` —— 核心 DLL
- `build/dstalk_cli/dstalk_cli.exe` —— 命令行前端
- `build/plugins/*.dll` —— 功能插件
**Mac / Linux:**
```bash
bash build.sh
```
编译产物输出到 `build/` 目录:
| 产物 | Windows | Mac | Linux |
|------|---------|-----|-------|
| 核心 DLL | `build/bin/dstalk.dll` | `build/bin/libdstalk.dylib` | `build/bin/libdstalk.so` |
| CLI 前端 | `build/bin/dstalk_cli.exe` | `build/bin/dstalk_cli` | `build/bin/dstalk_cli` |
| 功能插件 | `build/plugins/*.dll` | `build/plugins/*.dylib` | `build/plugins/*.so` |
---
@@ -49,15 +79,15 @@ build.bat
**config.toml 示例:**
```toml
# 选择 AI 后端插件: ai.openai 或 ai.anthropic
ai.provider = "ai.openai"
# 选择 AI 后端插件: ai_openai 或 ai_anthropic
ai.provider = "ai_openai"
# OpenAI-compatible
api.base_url = "https://api.openai.com/v1"
api.api_key = "sk-xxxxxxxx"
api.model = "gpt-4o"
# Anthropic Claude (切换 ai.provider 为 "ai.anthropic" 即可)
# Anthropic Claude (切换 ai.provider 为 "ai_anthropic" 即可)
# api.base_url = "https://api.anthropic.com/v1"
# api.api_key = "sk-ant-xxxxxxxx"
# api.model = "claude-opus-4-20250514"
@@ -71,8 +101,14 @@ api.model = "gpt-4o"
## 4. 运行 dstalk_cli
**Windows:**
```bash
build/dstalk_cli/dstalk_cli.exe
build\bin\dstalk_cli.exe
```
**Mac / Linux:**
```bash
build/bin/dstalk_cli
```
启动后显示欢迎横幅: