feat: add OpenAI-compatible AI provider plugin with SSE streaming support

- Implemented the OpenAI-compatible AI provider plugin, including configuration, chat, and chat_stream functionalities.
- Added support for SSE streaming and tool calls.
- Integrated Boost.JSON for JSON handling.
- Created CMake configuration for the plugin.
- Added error handling and logging throughout the plugin.
This commit is contained in:
2026-05-31 05:37:04 +08:00
parent f6cb51b40a
commit ba7382db2a
61 changed files with 163 additions and 147 deletions

View File

@@ -18,11 +18,11 @@ add_test(NAME dstalk-smoke-test COMMAND dstalk-smoke-test)
add_executable(dstalk-host-api-test
host_api_test.cpp
${CMAKE_SOURCE_DIR}/dstalk-core/src/service_registry.cpp
${CMAKE_SOURCE_DIR}/dstalk_core/src/service_registry.cpp
)
target_include_directories(dstalk-host-api-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/src
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
)
target_compile_features(dstalk-host-api-test
@@ -41,11 +41,11 @@ add_test(NAME dstalk-host-api-test COMMAND dstalk-host-api-test)
add_executable(dstalk-event-bus-test
event_bus_test.cpp
${CMAKE_SOURCE_DIR}/dstalk-core/src/event_bus.cpp
${CMAKE_SOURCE_DIR}/dstalk_core/src/event_bus.cpp
)
target_include_directories(dstalk-event-bus-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/src
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
)
target_compile_features(dstalk-event-bus-test
@@ -60,11 +60,11 @@ add_test(NAME dstalk-event-bus-test COMMAND dstalk-event-bus-test)
add_executable(dstalk-service-registry-test
service_registry_test.cpp
${CMAKE_SOURCE_DIR}/dstalk-core/src/service_registry.cpp
${CMAKE_SOURCE_DIR}/dstalk_core/src/service_registry.cpp
)
target_include_directories(dstalk-service-registry-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/src
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
)
target_compile_features(dstalk-service-registry-test
@@ -95,12 +95,12 @@ add_test(NAME dstalk-context-plugin-test COMMAND dstalk-context-plugin-test)
add_executable(dstalk-plugin-loader-test
plugin_loader_test.cpp
${CMAKE_SOURCE_DIR}/dstalk-core/src/plugin_loader.cpp
${CMAKE_SOURCE_DIR}/dstalk-core/src/boost_json.cpp
${CMAKE_SOURCE_DIR}/dstalk_core/src/plugin_loader.cpp
${CMAKE_SOURCE_DIR}/dstalk_core/src/boost_json.cpp
)
target_include_directories(dstalk-plugin-loader-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/src
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/src
)
target_compile_features(dstalk-plugin-loader-test
@@ -134,7 +134,7 @@ add_executable(dstalk-anthropic-plugin-test
)
target_include_directories(dstalk-anthropic-plugin-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/include
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
)
target_compile_definitions(dstalk-anthropic-plugin-test
@@ -161,7 +161,7 @@ add_executable(dstalk-openai-plugin-test
)
target_include_directories(dstalk-openai-plugin-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/include
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
)
target_compile_definitions(dstalk-openai-plugin-test
@@ -190,7 +190,7 @@ add_executable(dstalk-network-plugin-test
)
target_include_directories(dstalk-network-plugin-test
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk-core/include
PRIVATE ${CMAKE_SOURCE_DIR}/dstalk_core/include
)
target_compile_definitions(dstalk-network-plugin-test

View File

@@ -9,7 +9,7 @@
*/
#define BOOST_JSON_HEADER_ONLY
#define BOOST_ALL_NO_LIB
#include "../plugins/anthropic/src/anthropic_plugin.cpp"
#include "../plugins_upper/anthropic/src/anthropic_plugin.cpp"
#include <cstring>
#include <iostream>

View File

@@ -9,7 +9,7 @@
*/
#define _CRT_SECURE_NO_WARNINGS
#define BOOST_ASIO_DISABLE_STD_TO_ADDRESS
#include "../plugins/network/src/network_plugin.cpp"
#include "../plugins_middle/network/src/network_plugin.cpp"
#include <cstdio>
#include <cstdlib>

View File

@@ -9,7 +9,7 @@
*/
#define BOOST_JSON_HEADER_ONLY
#define BOOST_ALL_NO_LIB
#include "../plugins/openai/src/openai_plugin.cpp"
#include "../plugins_upper/openai/src/openai_plugin.cpp"
#include <cstring>
#include <iostream>

View File

@@ -82,8 +82,8 @@ static void reset_log_state() {
g_last_log_msg[0] = '\0';
}
// Get the absolute path to the build output plugins/ directory
// 获取构建输出 plugins/ 目录的绝对路径
// Get the absolute path to the plugin tier directory (plugins_base / middle / upper)
// 获取插件层级目录 (plugins_base / middle / upper) 的绝对路径
static fs::path get_plugins_dir() {
#ifdef DSTALK_TEST_PLUGINS_DIR
return fs::path(DSTALK_TEST_PLUGINS_DIR);
@@ -121,10 +121,10 @@ int main()
CHECK(loader.load_plugin("../plugins/test.dll") == -1,
"T1.3: ../ traversal rejected");
// T1.4: 不在 plugins/ 目录下 / not under plugins/ dir
// T1.4: 不在插件 tier 目录下 / not under plugin tier dir
auto tmp = fs::temp_directory_path() / "dstalk_test_no_plugins" / "test.dll";
CHECK(loader.load_plugin(tmp.string().c_str()) == -1,
"T1.4: path not under plugins/ dir rejected");
"T1.4: path not under plugin tier dir rejected");
// T1.5: 路径中间的 .. 段 / .. segment in middle of path
CHECK(loader.load_plugin("plugins/../secret/test.dll") == -1,
@@ -134,9 +134,9 @@ int main()
CHECK(loader.load_plugin("plugins/test") == -1,
"T1.6: no extension rejected");
// T1.7: 合法扩展名但不在 plugins/ 下 / valid extension but not under plugins/
// T1.7: 合法扩展名但不在插件 tier 目录下 / valid extension but not under plugin tier dir
CHECK(loader.load_plugin("/etc/someconfig.so") == -1,
"T1.7: .so extension but not under plugins/ rejected");
"T1.7: .so extension but not under plugin tier dir rejected");
}
// ========================================================================
@@ -149,7 +149,7 @@ int main()
fs::path plugins_dir = get_plugins_dir();
fs::path dll_config = plugins_dir / "plugin-config.dll";
fs::path dll_fileio = plugins_dir / "plugin-file-io.dll";
fs::path dll_fileio = plugins_dir / "plugin-file_io.dll";
bool have_plugins = fs::exists(dll_config) && fs::exists(dll_fileio);
@@ -206,7 +206,7 @@ int main()
fs::path plugins_dir = get_plugins_dir();
std::vector<fs::path> dlls;
for (auto name : {"plugin-config.dll", "plugin-file-io.dll",
for (auto name : {"plugin-config.dll", "plugin-file_io.dll",
"plugin-context.dll", "plugin-session.dll"}) {
fs::path p = plugins_dir / name;
if (fs::exists(p)) dlls.push_back(p);

View File

@@ -58,7 +58,7 @@ int main()
<< "model = \"gpt-4o\"\n";
}
// 初始化主机(会自动扫描 plugins/ 加载插件)/ Init host (auto-scans plugins/ to load plugins)
// 初始化主机(会自动扫描 plugins_base/middle/upper 加载插件)/ Init host (auto-scans plugins_base/middle/upper to load plugins)
if (dstalk_init(config_path.string().c_str()) != 0) {
std::cerr << "dstalk_init failed\n";
return 1;
@@ -112,7 +112,7 @@ int main()
return 1;
}
} else {
std::cerr << "[WARN] file_io service not found (plugin may not be in plugins/ dir)\n";
std::cerr << "[WARN] file_io service not found (plugin may not be in plugins_base/ dir)\n";
}
// 测试服务查询: session / Test service query: session