From 1f5698e3e9029b69b2ea341884e860d82863020f Mon Sep 17 00:00:00 2001 From: Flywm Date: Fri, 5 Jun 2026 17:55:45 +0800 Subject: [PATCH 1/7] =?UTF-8?q?docs(modelinfo):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=B8=B0=E5=AF=8C=E6=A8=A1=E5=9E=8B=E4=BF=A1=E6=81=AFOpenSpec?= =?UTF-8?q?=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 问题描述:当前文本模型信息接口缺少模型参数量和模态能力的规范约束,需要先沉淀OpenSpec变更以明确公共API、JSON兼容策略和测试范围。 2. 解决方案:新增enrich-model-info变更,补充proposal、design、model-info规格和任务清单,约定parameterCount、capabilities以及text/image/audio/video能力范围。 3. 自测内容:x86_64环境执行openspec status --change "enrich-model-info" --json通过;本次仅提交规范文档,无架构相关二进制产物。 4. 影响域分析:影响OpenSpec规范目录,为后续SDK实现和评审提供依据;不改变编译产物、运行时协议或公共头文件。 5. 单元测试,理由:否。本次为规范文档提交,无可执行代码;通过OpenSpec状态校验确认proposal、design、specs、tasks完整。 6. 补充说明:代码实现改动未纳入本次提交,将作为后续实现提交单独处理。 Task: #638997 From: kylin Severity: Important Change-Id: I4a7f58489ad9f1ef99e0c729256a1edd70c5de23 --- .../changes/enrich-model-info/.openspec.yaml | 2 + openspec/changes/enrich-model-info/design.md | 102 ++++++++++++++++++ .../changes/enrich-model-info/proposal.md | 29 +++++ .../specs/model-info/spec.md | 62 +++++++++++ openspec/changes/enrich-model-info/tasks.md | 24 +++++ 5 files changed, 219 insertions(+) create mode 100644 openspec/changes/enrich-model-info/.openspec.yaml create mode 100644 openspec/changes/enrich-model-info/design.md create mode 100644 openspec/changes/enrich-model-info/proposal.md create mode 100644 openspec/changes/enrich-model-info/specs/model-info/spec.md create mode 100644 openspec/changes/enrich-model-info/tasks.md diff --git a/openspec/changes/enrich-model-info/.openspec.yaml b/openspec/changes/enrich-model-info/.openspec.yaml new file mode 100644 index 0000000..f617bd1 --- /dev/null +++ b/openspec/changes/enrich-model-info/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-04 diff --git a/openspec/changes/enrich-model-info/design.md b/openspec/changes/enrich-model-info/design.md new file mode 100644 index 0000000..7d9085e --- /dev/null +++ b/openspec/changes/enrich-model-info/design.md @@ -0,0 +1,102 @@ +## 上下文 + +`libkysdk-genai` 通过 `include/kylin-ai/genai/text/modelinfo.h` 中的 `TextModelList` 和 `TextModelInfo` 暴露文本模型元数据。SDK 当前已经在 `_TextModelList` 中解析 runtime JSON,并通过 C ABI getter 暴露各字段,同时保持公共结构体不透明。 + +现有元数据覆盖模型标识、展示名称、部署类型、品牌,以及联网搜索、思考、思考开关、工具选择等文本模型特性。它尚未暴露机器可读的模型规模,也没有暴露通用的模态能力,因此调用方无法在没有额外先验知识的情况下筛选本地大模型或多模态模型。 + +约束: + +- 通过继续保持 `TextModelInfo` 和 `TextModelList` 不透明来维持 ABI 兼容。 +- 保持现有调用方源码兼容,并兼容旧 runtime JSON payload。 +- 继续基于 JSON 做 runtime 集成,避免为了纯元数据扩展新增 D-Bus 方法。 +- 测试必须保持 hermetic,不依赖真实 D-Bus 服务或网络访问。 + +## 目标 / 非目标 + +**目标:** + +- 以机器可读的无符号整数暴露模型参数量。 +- 以能力位掩码暴露文本、图像、音频、视频能力。 +- 提供遵循现有错误码模式的 C ABI getter。 +- 将新增模型列表 JSON 字段作为可选字段解析,使旧 runtime 保持兼容。 +- 增加聚焦的单元测试,覆盖 JSON 解析、访问器、默认值、非法类型和能力查询。 + +**非目标:** + +- 不替换现有 `get_nlp_model_list` D-Bus 方法。 +- 不在本变更中创建跨模块的 vision 模型注册表。 +- 不删除或重新解释现有特性字段,例如 `supportsWebSearch`、`supportsThinking` 或 `supportsToolChoice`。 +- 第一版不引入本地化的参数量展示字符串;调用方可自行格式化数值。 +- 第一版不区分输入能力和输出能力。 + +## 决策 + +### 在现有模型列表 payload 中增加可选字段 + +runtime JSON 可以包含: + +```json +{ + "modelInfos": [ + { + "modelName": "qwen2.5-vl-7b", + "displayName": "Qwen2.5 VL 7B", + "deployType": 0, + "parameterCount": 7000000000, + "capabilities": ["text", "image"] + } + ] +} +``` + +理由:SDK 已经将模型列表数据视为 JSON,并且可以在不改变 D-Bus 方法签名的前提下解析可选字段。这能最小化 runtime/API 协同成本,并保持旧 runtime 有效。 + +备选方案:为增强元数据新增 D-Bus 方法。这会让版本管理更显式,但在这些数据仍属于现有模型列表契约时没有必要。 + +### 参数量使用 `uint64_t` + +`parameterCount` 将在内部以无符号 64 位整数存储,并通过返回 `uint64_t` 的 getter 暴露。字段缺失、负数、非数值或超出范围时默认返回 `0`。 + +理由:参数量可能超过 32 位范围,并且调用方需要机器可读的值来排序和过滤。`0` 是清晰的未知/默认哨兵值。 + +备选方案:暴露 `"7B"` 这类字符串。这对 UI 展示方便,但不利于排序、过滤和本地化。 + +### 使用能力位掩码,而不是为每种能力增加一个 getter + +公共 API 将定义文本、图像、音频、视频的能力位。`TextModelInfo` 将暴露完整掩码,并提供辅助判断函数。 + +理由:位掩码能保持 ABI 紧凑,并让未来新增能力保持源码兼容。每种模态一个 bool getter 会导致 API 线性膨胀,并且每新增一种能力都需要增加导出函数。 + +备选方案:暴露能力名称字符串数组。这可以保留未知值,但需要额外的数组和字符串所有权/生命周期 API。当前 SDK 的模型信息 API 以 getter 为主,更适合使用固定掩码并预留未来能力位。 + +### 特性标志与能力保持独立 + +现有字段 `supportsWebSearch`、`supportsThinking`、`supportsToolChoice` 保持不变。新的能力掩码描述宽泛的模型模态/任务支持,而不是每次请求的特性开关或供应商侧工具。 + +理由:将模态支持与特性标志混合会让 UI 过滤语义变得模糊。一个模型支持文本和工具选择,并不等价于它支持图像输入或音频能力。 + +### 能力名称区分大小写,并忽略未知名称 + +解析器会将已知 JSON 能力字符串映射到能力位,并忽略未知名称。`capabilities` 类型非法时默认使用空掩码,不跳过整个模型条目。 + +理由:这能保持前向兼容。runtime 可能先于 SDK 开始输出新的能力名称,旧 SDK 不应因此解析失败。 + +## 风险 / 取舍 + +- Runtime 将参数量以字符串输出 -> SDK 会默认返回 `0`;缓解方式:文档明确 `parameterCount` 为数值字段,并增加错误类型默认值测试。 +- 后续需要区分能力方向 -> 当前掩码无法区分图像输入和图像生成;缓解方式:保持本变更范围收敛,并在产品需求明确时为输入/输出能力掩码预留后续 API 空间。 +- 未知能力会被静默忽略 -> 使用旧 SDK 的调用方看不到新能力;缓解方式:这比解析失败更安全,也符合可选字段兼容策略。 +- `getModelList` 当前存在与本变更无关的成功/错误码细节问题 -> 除非实现阶段确认需要窄范围修复并用测试捕获,否则避免扩大行为变更。 + +## 迁移计划 + +- Runtime 可以开始在 `modelInfos[]` 条目中增加 `parameterCount` 和 `capabilities`。 +- 使用本变更构建的 SDK 将通过新增 getter 暴露这些字段。 +- 现有应用继续使用旧 getter,不需要修改。 +- 省略新增字段的旧 runtime 仍然有效;应用会获得参数量 `0` 和空能力掩码。 +- 回滚简单,因为新增 JSON 字段是可选字段,旧 SDK 会忽略它们。 + +## 待确认问题 + +- 后续是否需要区分输入能力和输出能力,例如图像输入与图像生成? +- 面向 UI 的 SDK helper 后续是否需要暴露 `7B` 或 `14B` 这类格式化参数量字符串? diff --git a/openspec/changes/enrich-model-info/proposal.md b/openspec/changes/enrich-model-info/proposal.md new file mode 100644 index 0000000..00b75a9 --- /dev/null +++ b/openspec/changes/enrich-model-info/proposal.md @@ -0,0 +1,29 @@ +## 为什么 + +当前应用可以列出文本模型并读取基础展示信息、部署类型等字段,但在选择模型前无法可靠获知模型规模或模态能力。随着模型目录开始同时包含本地模型、云端模型和多模态模型,调用方需要稳定的模型元数据来支撑 UI 过滤、能力判断和请求路由。 + +## 变更内容 + +- 为 `TextModelInfo` 增加模型参数量元数据。 +- 增加模型能力元数据,用于描述文本、图像、音频、视频等模态支持。 +- 增加 C ABI 访问器,使调用方无需直接解析 JSON 即可读取参数量并查询能力。 +- 扩展 runtime 模型列表 JSON 解析,新增字段按可选字段处理并保持向后兼容。 +- 保持现有模型元数据 API 和现有 runtime JSON 字段兼容;本变更不计划引入破坏性变更。 + +## 能力 + +### 新增能力 + +- `model-info`:定义文本模型列表 API 暴露的模型元数据契约,包括模型规模和能力发现。 + +### 修改能力 + +- 无。 + +## 影响范围 + +- 公共 API:`include/kylin-ai/genai/text/modelinfo.h` +- NLP 模型元数据解析:`src/nlp/_textmodelinfo.h`、`src/nlp/_textmodelinfo.cpp` +- Runtime 集成:`src/nlp/genainlpserviceproxy.cpp` 继续消费现有模型列表 JSON,并透传新支持的可选字段 +- 测试:`tests/nlp/textmodelinfo_test.cpp`、`tests/nlp/genaitextsession_test.cpp`,以及必要的 mock service fixture +- Runtime 契约:`get_nlp_model_list` JSON 可以包含新的可选元数据字段,旧 payload 仍然有效 diff --git a/openspec/changes/enrich-model-info/specs/model-info/spec.md b/openspec/changes/enrich-model-info/specs/model-info/spec.md new file mode 100644 index 0000000..1b4ed28 --- /dev/null +++ b/openspec/changes/enrich-model-info/specs/model-info/spec.md @@ -0,0 +1,62 @@ +## ADDED Requirements + +### Requirement: 模型参数量元数据 +SDK SHALL 为模型列表 API 返回的每个文本模型暴露机器可读的参数量。 + +#### Scenario: 参数量可用 +- **WHEN** runtime 模型列表 JSON 的模型条目包含数值类型的 `parameterCount` 字段 +- **THEN** SDK SHALL 通过模型信息参数量访问器返回该值 + +#### Scenario: 参数量缺失 +- **WHEN** runtime 模型列表 JSON 的模型条目省略 `parameterCount` +- **THEN** SDK SHALL 保持该模型条目有效,并将其参数量返回为 `0` + +#### Scenario: 参数量类型非法 +- **WHEN** runtime 模型列表 JSON 包含非数值或其他非法的 `parameterCount` 值 +- **THEN** SDK SHALL 保持该模型条目有效,并将其参数量返回为 `0` + +#### Scenario: 空模型信息参数量访问 +- **WHEN** 调用参数量访问器时传入 `NULL` 模型信息 +- **THEN** SDK SHALL 返回 `0`,并通过可选错误码输出报告 `AI_COMMON_INVALID_PARAMETER` + +### Requirement: 模型能力元数据 +SDK SHALL 为模型列表 API 返回的每个文本模型暴露模型能力掩码,覆盖文本、图像、音频和视频能力。 + +#### Scenario: 能力可用 +- **WHEN** runtime 模型列表 JSON 的模型条目包含已知能力名称 +- **THEN** SDK SHALL 将这些名称映射到对应的公共能力位 + +#### Scenario: 能力缺失 +- **WHEN** runtime 模型列表 JSON 的模型条目省略 `capabilities` +- **THEN** SDK SHALL 保持该模型条目有效,并返回空能力掩码 + +#### Scenario: 能力列表包含未知名称 +- **WHEN** runtime 模型列表 JSON 包含 SDK 无法识别的能力名称 +- **THEN** SDK SHALL 忽略未知名称,并保留所有已识别能力位 + +#### Scenario: 能力列表类型非法 +- **WHEN** runtime 模型列表 JSON 包含非数组或其他非法的 `capabilities` 值 +- **THEN** SDK SHALL 保持该模型条目有效,并返回空能力掩码 + +#### Scenario: 能力判断查询受支持能力 +- **WHEN** 调用方查询模型是否支持其能力掩码中包含的能力 +- **THEN** SDK SHALL 返回 `true`,并通过可选错误码输出报告成功 + +#### Scenario: 能力判断查询不受支持能力 +- **WHEN** 调用方查询模型是否支持其能力掩码中不包含的能力 +- **THEN** SDK SHALL 返回 `false`,并通过可选错误码输出报告成功 + +#### Scenario: 空模型信息能力访问 +- **WHEN** 调用能力访问器时传入 `NULL` 模型信息 +- **THEN** SDK SHALL 返回默认的 false 或空掩码值,并通过可选错误码输出报告 `AI_COMMON_INVALID_PARAMETER` + +### Requirement: 向后兼容的模型列表解析 +SDK SHALL 将增强模型元数据字段作为现有模型列表 JSON 契约的可选扩展处理。 + +#### Scenario: 解析旧 runtime payload +- **WHEN** runtime 模型列表 JSON 只包含现有必填字段 `modelName`、`displayName` 和 `deployType` +- **THEN** SDK SHALL 继续暴露该模型条目,并为增强元数据返回默认值 + +#### Scenario: 现有特性标志保持独立 +- **WHEN** runtime 模型列表 JSON 包含 `supportsWebSearch`、`supportsThinking` 或 `supportsToolChoice` 等现有特性标志 +- **THEN** SDK SHALL 独立于新能力掩码解析这些特性标志 diff --git a/openspec/changes/enrich-model-info/tasks.md b/openspec/changes/enrich-model-info/tasks.md new file mode 100644 index 0000000..f10f995 --- /dev/null +++ b/openspec/changes/enrich-model-info/tasks.md @@ -0,0 +1,24 @@ +## 1. 公共 API 契约 + +- [x] 1.1 在 `include/kylin-ai/genai/text/modelinfo.h` 中新增公共模型能力常量/类型定义,覆盖 text、image、audio 和 video。 +- [x] 1.2 新增公共 C ABI 声明,用于读取参数量、读取能力掩码,以及检查 `TextModelInfo` 是否支持某一能力。 +- [x] 1.3 更新 `modelinfo.h` 中的 Doxygen 注释,说明新增访问器的默认值、可选错误码行为和 SDK 拥有的生命周期语义。 + +## 2. 元数据解析 + +- [x] 2.1 扩展 `src/nlp/_textmodelinfo.h` 中的 `_TextModelInfo`,使用 ABI 安全的内部字段保存参数量和能力掩码。 +- [x] 2.2 扩展 `src/nlp/_textmodelinfo.cpp` 中的 `_TextModelList` JSON 解析,解析可选数值字段 `parameterCount` 和字符串数组字段 `capabilities`。 +- [x] 2.3 实现已知能力名称映射,并在不拒绝模型条目的前提下忽略未知能力字符串。 +- [x] 2.4 按现有错误码约定和 NULL/default 处理方式实现新的公共访问器函数。 + +## 3. Runtime 兼容性 + +- [x] 3.1 验证 `GenAiNlpServiceProxy::getModelList` 在不修改 D-Bus 方法的情况下,继续将增强模型列表 JSON 交给现有解析器处理。 +- [x] 3.2 仅在需要通过现有 proxy/session 路径覆盖增强元数据时,更新 mock D-Bus 模型列表 fixture。 + +## 4. 测试与验证 + +- [x] 4.1 扩展 `tests/nlp/textmodelinfo_test.cpp`,覆盖合法参数量和能力解析。 +- [x] 4.2 增加字段缺失、字段类型错误、未知能力名称、空模型信息访问器和空错误码输出测试。 +- [x] 4.3 增加或更新 session/proxy 测试,验证 mock fixture 提供增强元数据时,数据能通过 `genai_text_get_model_list` 路径保留。 +- [x] 4.4 在 60 秒单元测试限制内运行聚焦 NLP 测试,并记录当前环境无法运行的更大范围测试命令。 -- Gitee From aebb28741c4b3d46c0e855b71f28e23d33b6cfe1 Mon Sep 17 00:00:00 2001 From: liqi Date: Tue, 30 Jun 2026 09:08:34 +0800 Subject: [PATCH 2/7] =?UTF-8?q?fix(nlp):=20=E8=A7=A3=E5=86=B3=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E7=94=A8=E6=8E=A5=E5=8F=A3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=92=8CJSON=E8=A7=A3=E6=9E=90=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了tool_calls_json和result_json空指针检查 - 修复了会话ID小于等于0的验证逻辑 - 更新了JSON解析方法以提高安全性 - 使用Json::Reader替代stringToJson函数进行解析 - 添加了JSON字符串为空的检查 - 改进了错误处理机制 Task: #558007 From: kylin Severity: Important Change-Id: Ib2faa63b21deda603996b6ae93d1443f585ae2b3 --- src/nlp/_toolchoice.cpp | 3 ++ src/nlp/genainlpserviceproxy.cpp | 55 ++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/nlp/_toolchoice.cpp b/src/nlp/_toolchoice.cpp index 00d5390..47c48b5 100644 --- a/src/nlp/_toolchoice.cpp +++ b/src/nlp/_toolchoice.cpp @@ -77,6 +77,9 @@ int genai_text_submit_tool_result(GenAiTextSession* session, const char* tool_ca if (session == nullptr) { return AI_COMMON_INVALID_SESSION; } + if (tool_calls_json == nullptr || result_json == nullptr) { + return AI_COMMON_NLP_PARAM_ERROR; + } return session->submitToolResult(tool_calls_json, result_json); } diff --git a/src/nlp/genainlpserviceproxy.cpp b/src/nlp/genainlpserviceproxy.cpp index 00286bb..a96f7a0 100644 --- a/src/nlp/genainlpserviceproxy.cpp +++ b/src/nlp/genainlpserviceproxy.cpp @@ -31,16 +31,14 @@ #include "src/nlp/logger.h" namespace kyai::genai::nlp { - const char* objectPath = "/com/kylin/AiRuntime/GenAiNlp"; const char* interface = "com.kylin.AiRuntime.GenAiNlp"; const char* nlpResultSignal = "ChatNlpResult"; const char* toolHandlerResultSignal = "ToolHandlerResult"; -const int chatResultCallbackTimeoutMs = 60 * 60 * 1000; // 1 hour timeout +const int chatResultCallbackTimeoutMs = 60 * 60 * 1000; // 1 hour timeout namespace { - ChatResult dissectChatResult(GVariant* parameters) { GVariantIter iter; g_variant_iter_init(&iter, parameters); @@ -102,8 +100,8 @@ ChatResult dissectChatResult(GVariant* parameters) { return {}; } - ChatResult result{resultReason, resultReasoningContent, resultFinishReason, resultModelName, - *resultErrorCode, resultErrorMessage, *resultIsEnd}; + ChatResult result{resultReason, resultReasoningContent, resultFinishReason, resultModelName, + *resultErrorCode, resultErrorMessage, *resultIsEnd}; result.requestId_ = resultRequestId; _ChatResultSearchInfo chatResultSearchInfo(resultSearchInfo); @@ -178,8 +176,7 @@ void reconnectSleep() { std::this_thread::sleep_for(std::chrono::seconds(1)); #endif } - -} // namespace +} // namespace GenAiNlpServiceProxy::~GenAiNlpServiceProxy() { if (chatSubscriptionConnection_ != nullptr) { @@ -236,6 +233,7 @@ bool GenAiNlpServiceProxy::connectToServer() { return true; } + int GenAiNlpServiceProxy::initEngine(const ChatModelConfig& chatModelConfig, int* sessionId) { Json::Value chatModelConfigJson = modelConfigToJson(chatModelConfig); std::string config = jsonToString(chatModelConfigJson); @@ -658,6 +656,10 @@ int GenAiNlpServiceProxy::registerTool(int sessionId, const std::string& toolNam if (!ensureProtocolSupportedForApi("register_tool", &errorCode)) { return errorCode; } + if (sessionId <= 0) { + LOGE("sessionId is invalid,{}", sessionId); + return AI_COMMON_INVALID_SESSION; + } if (toolName.empty()) { LOGE("toolName is empty"); return AI_COMMON_NLP_PARAM_ERROR; @@ -696,6 +698,10 @@ int GenAiNlpServiceProxy::clearTools(int sessionId) { if (!ensureProtocolSupportedForApi("clear_tools", &errorCode)) { return errorCode; } + if (sessionId <= 0) { + LOGE("sessionId is invalid,{}", sessionId); + return AI_COMMON_INVALID_SESSION; + } GError* error = nullptr; bool success = ai_runtime_gen_ai_nlp_service_call_clear_tools_sync(proxy_, sessionId, &errorCode, nullptr, &error); if (not success) { @@ -714,15 +720,25 @@ int GenAiNlpServiceProxy::submitToolResult(int sessionId, const ChatModelConfig& if (!ensureProtocolSupportedForApi("submit_tool_result", &errorCode)) { return errorCode; } - Json::Value toolCalls = stringToJson(toolCallsJson); - if (toolCalls.isNull()) { - LOGE("toolCallsJson is invalid"); - return AI_COMMON_NLP_PARAM_ERROR; + if (sessionId <= 0) { + LOGE("sessionId is invalid,{}", sessionId); + return AI_COMMON_INVALID_SESSION; } - Json::Value result = stringToJson(resultJson); - if (result.isNull()) { - LOGE("resultJson is invalid"); - return AI_COMMON_NLP_PARAM_ERROR; + Json::Value toolCalls; + { + Json::Reader reader; + if (toolCallsJson.empty() || !reader.parse(toolCallsJson, toolCalls)) { + LOGE("toolCallsJson is invalid"); + return AI_COMMON_NLP_PARAM_ERROR; + } + } + Json::Value result; + { + Json::Reader reader; + if (resultJson.empty() || !reader.parse(resultJson, result)) { + LOGE("resultJson is invalid"); + return AI_COMMON_NLP_PARAM_ERROR; + } } Json::Value config = modelConfigToJson(chatModelConfig); config["tool_calls"] = toolCalls; @@ -928,8 +944,8 @@ void GenAiNlpServiceProxy::startCallbackTimer() { [](gpointer data) -> gboolean { auto* proxy = static_cast(data); proxy->handleCallbackTimeout(); - proxy->timeoutId_ = 0; // Reset the ID since the source is removed - return G_SOURCE_REMOVE; // Don't repeat the timeout + proxy->timeoutId_ = 0; // Reset the ID since the source is removed + return G_SOURCE_REMOVE; // Don't repeat the timeout }, this); } @@ -952,7 +968,7 @@ void GenAiNlpServiceProxy::handleCallbackTimeout() { stopChat(currentSessionId_); if (chatResultCallback_) { - ChatResult result{"", "", "", "", AISDK_MODEL_RUN_TIME_OUT, "NLP result callback timeout after 2 minutes", + ChatResult result{"", "", "", "", AISDK_MODEL_RUN_TIME_OUT, "NLP result callback timeout after 2 minutes", true}; chatResultCallback_(&result, userData_); } @@ -1000,5 +1016,4 @@ bool GenAiNlpServiceProxy::ensureProtocolSupportedForApi(const char* apiName, in return false; } - -} // namespace kyai::genai::nlp +} // namespace kyai::genai::nlp -- Gitee From 96a3cb8d3e7dc3cbcdf4f611f5567db9f2ee1f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=8F=AF=E5=BF=83?= Date: Mon, 29 Jun 2026 16:02:50 +0800 Subject: [PATCH 3/7] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E5=B8=A6?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E9=99=90=E5=88=B6=E7=9A=84=20Breaks/Replaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -补充 Breaks 字段,并将 Replaces 限制为早于当前二进制包版本的旧包, 确保升级过程中能够正确处理文件归属迁移 Task: #610987 From: kylin Severity: Important Changelog-Other: control文件添加带版本限制的 Breaks/Replaces Changelog-Break: 无 Change-Id: I2097ec98a55e6a7824a57b344ac0fe0446fa767c --- debian/control | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/debian/control b/debian/control index 707e045..24b0182 100644 --- a/debian/control +++ b/debian/control @@ -17,7 +17,10 @@ Architecture: any Multi-Arch: same Depends: ${misc:Depends}, ${shlibs:Depends}, Provides: libkysdk-genai-nlp0 (= ${binary:Version}), libkysdk-genai-vision0 (= ${binary:Version}) -Replaces: libkysdk-genai-nlp0, libkysdk-genai-vision0 +Replaces: libkysdk-genai-nlp0 (<< ${binary:Version}), + libkysdk-genai-vision0 (<< ${binary:Version}) +Breaks: libkysdk-genai-nlp0 (<< ${binary:Version}), + libkysdk-genai-vision0 (<< ${binary:Version}) Description: Kylin AI GenAI SDK shared libraries This package provides the Kylin GenAI shared libraries for text and vision features. @@ -28,7 +31,10 @@ Architecture: any Multi-Arch: same Depends: libkysdk-ai-common-dev, libkysdk-genai0 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} Provides: libkysdk-genai-nlp-dev (= ${binary:Version}), libkysdk-genai-vision-dev (= ${binary:Version}) -Replaces: libkysdk-genai-nlp-dev, libkysdk-genai-vision-dev +Replaces: libkysdk-genai-nlp-dev (<< ${binary:Version}), + libkysdk-genai-vision-dev (<< ${binary:Version}) +Breaks: libkysdk-genai-nlp-dev (<< ${binary:Version}), + libkysdk-genai-vision-dev (<< ${binary:Version}) Description: Development files for libkysdk-genai0 This package contains the header files, development symlinks, and pkg-config metadata for building applications against the Kylin GenAI -- Gitee From f3b0f705d218c889d8dd0edc66ff50a216c54ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=B8=81?= Date: Thu, 18 Jun 2026 17:34:28 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix(nlp):=20=E4=BD=BF=E7=94=A8=20libsodium?= =?UTF-8?q?=20=E6=9D=A5=E7=94=9F=E6=88=90=E9=9A=8F=E6=9C=BA=E7=9A=84?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 解决安全热点问题 Task: #634749 From: kylin Severity: Important Change-Id: I5343eaf33e634b3bcc3753af973a6cb3b5a8cdc0 --- CMakeLists.txt | 5 ++++- src/nlp/_genaitextsession.cpp | 12 +++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 771d1a7..3713195 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,9 @@ pkg_check_modules(GIO IMPORTED_TARGET gio-unix-2.0) # libkysdk-ai-common-dev pkg_check_modules(KYSDK_AI_COMMON IMPORTED_TARGET kysdk-ai-common) +# libsodium-dev +pkg_check_modules(SODIUM REQUIRED IMPORTED_TARGET libsodium) + kylin_ai_generate_gdbus_proto_code(GENAI_NLP_PROTO_FILES gennlpservice) add_library(kysdk-genai-nlp SHARED @@ -66,7 +69,7 @@ add_library(kysdk-genai-nlp SHARED set_target_properties(kysdk-genai-nlp PROPERTIES VERSION 1.0.0 SOVERSION 1) -target_link_libraries(kysdk-genai-nlp jsoncpp PkgConfig::GIO PkgConfig::KYSDK_AI_COMMON) +target_link_libraries(kysdk-genai-nlp jsoncpp PkgConfig::GIO PkgConfig::KYSDK_AI_COMMON PkgConfig::SODIUM) kylin_ai_generate_gdbus_proto_code(GENAI_VISION_PROTO_FILES genaivisionservice) diff --git a/src/nlp/_genaitextsession.cpp b/src/nlp/_genaitextsession.cpp index 681e05b..55689a6 100644 --- a/src/nlp/_genaitextsession.cpp +++ b/src/nlp/_genaitextsession.cpp @@ -17,9 +17,11 @@ #include "_genaitextsession.h" +#include #include #include -#include + +#include #include "include/kylin-ai/genai/text/chat.h" #include "include/kylin-ai/genai/text/error.h" @@ -36,12 +38,12 @@ void setErrorCode(int *pErrorCode, int errorCode) { std::string generateRequestId() { static constexpr char kHexDigits[] = "0123456789abcdef"; - static thread_local std::mt19937 rng(std::random_device{}()); - std::uniform_int_distribution dist(0, 255); + std::array randomBytes{}; + randombytes_buf(randomBytes.data(), randomBytes.size()); + std::string requestId; requestId.reserve(32); - for (int i = 0; i < 16; ++i) { - const unsigned value = static_cast(dist(rng)); + for (const unsigned char value : randomBytes) { requestId.push_back(kHexDigits[(value >> 4) & 0x0F]); requestId.push_back(kHexDigits[value & 0x0F]); } -- Gitee From 141e81a6136163c60c0976e902b761485f0f02ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=B8=81?= Date: Thu, 18 Jun 2026 17:39:19 +0800 Subject: [PATCH 5/7] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E4=BE=9D=E8=B5=96=20libsodium?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加编译依赖 libsodium Task: #634749 From: kylin Severity: Important Change-Id: If1d743c2a24ba3dc1b74478601e4746fcc79b95a --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 24b0182..adf53a8 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Build-Depends: debhelper-compat (= 12), libglib2.0-dev, libjsoncpp-dev, libssl-dev, + libsodium-dev, libkylin-ai-system-private-dev, libkysdk-ai-common-dev, Rules-Requires-Root: binary-targets -- Gitee From 4888e69c93910da80a25691c7b42749a1ebec886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=B8=81?= Date: Mon, 22 Jun 2026 16:49:35 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8snprintf=E4=BB=A3?= =?UTF-8?q?=E6=9B=BFsprintf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 保证更加安全 Task: #634749 From: kylin Severity: Important Change-Id: Ib9173637e8ec52c680e095ffd12c67e9267c3a6a --- src/nlp/logger.cpp | 7 ++++--- src/vision/logger.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/nlp/logger.cpp b/src/nlp/logger.cpp index b11ae0d..7469417 100644 --- a/src/nlp/logger.cpp +++ b/src/nlp/logger.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -65,10 +66,10 @@ std::string Logger::currentTime() { tm = localtime(&tt); char buffer[32]{}; #ifdef RUN_IN_DEBUG - sprintf(buffer, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000); + std::snprintf(buffer, sizeof(buffer), "[%04d-%02d-%02d %02d:%02d:%02d.%03ld]", tm->tm_year + 1900, + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000); #else - sprintf(buffer, "[%ld]", tv.tv_sec * 1000 + tv.tv_usec / 1000); + std::snprintf(buffer, sizeof(buffer), "[%ld]", tv.tv_sec * 1000 + tv.tv_usec / 1000); #endif return buffer; } diff --git a/src/vision/logger.cpp b/src/vision/logger.cpp index ac917ff..083c5c9 100644 --- a/src/vision/logger.cpp +++ b/src/vision/logger.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -65,10 +66,10 @@ std::string Logger::currentTime() { tm = localtime(&tt); char buffer[32]{}; #ifdef RUN_IN_DEBUG - sprintf(buffer, "[%04d-%02d-%02d %02d:%02d:%02d.%03ld]", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000); + std::snprintf(buffer, sizeof(buffer), "[%04d-%02d-%02d %02d:%02d:%02d.%03ld]", tm->tm_year + 1900, + tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000); #else - sprintf(buffer, "[%ld]", tv.tv_sec * 1000 + tv.tv_usec / 1000); + std::snprintf(buffer, sizeof(buffer), "[%ld]", tv.tv_sec * 1000 + tv.tv_usec / 1000); #endif return buffer; } -- Gitee From 884a1aa05eeffc9f9786c4e6c47a035568c6e5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E4=B8=81?= Date: Sat, 27 Jun 2026 15:26:58 +0800 Subject: [PATCH 7/7] =?UTF-8?q?chore:=20=E8=A1=A5=E5=85=85=E7=89=88?= =?UTF-8?q?=E6=9D=83=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充麒麟版权头 Task: #617759 From: kylin Severity: Low Change-Id: I64f5fe7f2bd90aded713f1a3d712a7a15fec94ca --- src/nlp/protocolversion.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/nlp/protocolversion.cpp b/src/nlp/protocolversion.cpp index 005d8f8..a5bb0a8 100644 --- a/src/nlp/protocolversion.cpp +++ b/src/nlp/protocolversion.cpp @@ -1,3 +1,20 @@ +/* + * Copyright 2025 KylinSoft Co., Ltd. + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + #include "protocolversion.h" #include -- Gitee