Skip to content

Commit 88cbda7

Browse files
committed
fix(zhipu): 精确化 <None> 正则并原地更新 result_chain
根据 sourcery-ai review 意见进行以下修复: 1. _GLM_NULL_TOKEN_RE 移除 re.IGNORECASE:GLM 只输出精确的 <None>(大写 N),去掉不必要的大小写不敏感标志使正则更精确, 避免误匹配非 GLM 控制 token 的合法内容。 2. _parse_openai_completion 改用 completion_text setter 原地 更新文本,不再重建整个 result_chain,从而保留 tool call 等非文本组件,防止丢弃基础解析器生成的更丰富结构。 3. 同步更新测试:<none>/<NONE> 不再被清除,断言改为保留原文。
1 parent 7718523 commit 88cbda7

2 files changed

Lines changed: 12 additions & 9 deletions

File tree

astrbot/core/provider/sources/zhipu_source.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from openai.types.chat import ChatCompletion
88

99
from astrbot.core.agent.tool import ToolSet
10-
from astrbot.core.message.message_event_result import MessageChain
1110

1211
from ..entities import LLMResponse
1312
from ..register import register_provider_adapter
@@ -20,9 +19,11 @@
2019
re.IGNORECASE,
2120
)
2221

23-
# GLM's "null response" signal — the model outputs <None> (sometimes prefixed with
24-
# whitespace/newlines) to indicate it has nothing to say.
25-
_GLM_NULL_TOKEN_RE = re.compile(r"<None>", re.IGNORECASE)
22+
# GLM's "null response" signal — the model outputs exactly <None> (capital N, like Python's
23+
# None literal) to indicate it has nothing to say. We intentionally do NOT use re.IGNORECASE
24+
# here: GLM always emits <None> with a capital N, and a case-insensitive match could
25+
# accidentally remove unrelated HTML/XML-like content that merely starts with "none".
26+
_GLM_NULL_TOKEN_RE = re.compile(r"<None>")
2627

2728

2829
@register_provider_adapter("zhipu_chat_completion", "智谱 Chat Completion 提供商适配器")
@@ -70,11 +71,11 @@ async def _parse_openai_completion(
7071
llm_response = await super()._parse_openai_completion(completion, tools)
7172

7273
# Apply GLM special token cleaning to the assembled completion text.
74+
# Use the completion_text setter so that non-Plain components (e.g. tool calls)
75+
# in the chain are preserved; only the Plain text segments are updated in-place.
7376
if llm_response.completion_text:
7477
cleaned = self._clean_glm_special_tokens(llm_response.completion_text)
7578
if cleaned != llm_response.completion_text:
76-
llm_response.result_chain = (
77-
MessageChain().message(cleaned) if cleaned else MessageChain()
78-
)
79+
llm_response.completion_text = cleaned
7980

8081
return llm_response

tests/test_zhipu_source.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ def test_null_token_surrounded_by_whitespace(self):
6565
assert ProviderZhipu._clean_glm_special_tokens(" <None> ") == ""
6666

6767
def test_null_token_case_insensitive_lower(self):
68-
assert ProviderZhipu._clean_glm_special_tokens("<none>") == ""
68+
# Without re.IGNORECASE, lowercase <none> is not a GLM token and must be preserved.
69+
assert ProviderZhipu._clean_glm_special_tokens("<none>") == "<none>"
6970

7071
def test_null_token_case_insensitive_upper(self):
71-
assert ProviderZhipu._clean_glm_special_tokens("<NONE>") == ""
72+
# Without re.IGNORECASE, uppercase <NONE> is not a GLM token and must be preserved.
73+
assert ProviderZhipu._clean_glm_special_tokens("<NONE>") == "<NONE>"
7274

7375
def test_null_token_in_middle_of_text(self):
7476
result = ProviderZhipu._clean_glm_special_tokens("hello <None> world")

0 commit comments

Comments
 (0)