feat: Add LSP plugin unit tests and frontend common initialization library
Some checks failed
CI / Determine matrix (push) Has been cancelled
CI / Sanitizer (ASan+UBSan) / ubuntu-24.04 (push) Has been cancelled
CI / Coverage (gcovr) / ubuntu-24.04 (push) Has been cancelled
CI / ${{ matrix.os }} / ${{ matrix.build_type }} (push) Has been cancelled

- Introduced `dstalk_lsp_plugin_test` for testing LSP plugin functionalities including `lsp_trim`, `lsp_frame_message`, and `lsp_parse_content_length`.
- Created `dstalk_frontend_common` static library to encapsulate shared initialization logic for frontend components (CLI, GUI, Web).
- Implemented configuration file discovery and service querying in `dstalk_frontend_init`.
- Added internal headers for LSP and Anthropic plugins to facilitate unit testing.
- Established a mailroom system for asynchronous message passing between stateless agents, enhancing coordination and context management.
This commit is contained in:
2026-06-01 08:51:40 +08:00
parent 8faa02c3d5
commit c0af9c65c7
17 changed files with 1235 additions and 69 deletions

View File

@@ -16,5 +16,6 @@ set_target_properties(dstalk_gui PROPERTIES
target_link_libraries(dstalk_gui
PRIVATE
dstalk
dstalk_frontend_common
SDL3::SDL3
)

View File

@@ -744,8 +744,23 @@ static void processEvent(AppContext& ctx, SDL_Event& ev) {
break;
case SDLK_O:
if (ctrl) {
// Ctrl+O加载会话 / Ctrl+O: load session
// Ctrl+O加载会话
if (g_session_svc && g_session_svc->load("session.json") == 0) {
// BUGFIX: 从 session 历史重建 GUI 消息列表
int hcount = 0;
const dstalk_message_t* history = g_session_svc->history(&hcount);
gs.messages.clear();
for (int i = 0; i < hcount; ++i) {
ChatMessage::Role r;
if (std::strcmp(history[i].role, "user") == 0)
r = ChatMessage::USER;
else if (std::strcmp(history[i].role, "assistant") == 0)
r = ChatMessage::ASSISTANT;
else
r = ChatMessage::SYSTEM;
gs.messages.push_back(ChatMessage(r,
history[i].content ? history[i].content : ""));
}
gs.messages.push_back(ChatMessage(
ChatMessage::SYSTEM, "Session loaded from session.json"));
} else {
@@ -895,8 +910,30 @@ int main(int argc, char* argv[]) {
g_ai_svc->free_result(&result);
}
// 流式传输完成(或被取消) / Streaming completed (or cancelled)
if (rc != 0) {
// 流式传输完成(或被取消)
if (rc == 0) {
// BUGFIX: 将用户消息和 AI 回复持久化到 session 服务
if (g_session_svc) {
const std::string& userContent =
ctx.state.messages[ctx.state.messages.size() - 2].content;
const std::string& aiContent =
ctx.state.messages.back().content;
dstalk_message_t user_msg = {
"user",
userContent.c_str(),
nullptr, nullptr
};
g_session_svc->add(&user_msg);
dstalk_message_t ai_msg = {
"assistant",
aiContent.c_str(),
nullptr, nullptr
};
g_session_svc->add(&ai_msg);
}
} else {
if (!ctx.state.messages.empty() &&
ctx.state.messages.back().role == ChatMessage::ASSISTANT) {
if (ctx.state.messages.back().content.empty()) {