From 924f11cac59ad0e81bbf559b15ea39d20b381f84 Mon Sep 17 00:00:00 2001 From: white Date: Sat, 19 Sep 2026 12:31:27 +0800 Subject: [PATCH] fix(ci): repair the lint and CRLF-fragile test gates on main Two independent defects broke the verification workflow on main: 1. `bun run lint` failed with 4x no-useless-assignment in src/controllers/anthropic.js. In handleAnthropicStream and handleAnthropicNonStream, `promptTokens`/`completionTokens` were initialised to 0 and then unconditionally overwritten from the authoritative usage object, so the initialisers were dead stores. Remove the write-only locals and take both values as consts directly from `usage` at the single point where they are resolved. No behavior change: the values consumed by attributeChatUsage and the emitted usage payload are identical. 2. tests/tool-prompt.test.js:805 failed on any CRLF checkout ("ningun sitio de prompt/hint re-ensena la forma nativa "). The per-line comment strip used a line-comment regex anchored with `$`, and on CRLF input the dot stops before the CR so `$` matches there; the match is not global, so the engine backtracked, matched the empty string, and left the comment body in `code`. The rationale comments that legitimately name `` then tripped the source scan. Bound the strip by the newline instead, which is what the test intends on both LF and CRLF checkouts. Verified locally: lint exit 0; frontend build exit 0; test gate PASS 1146 tests / 134 suites / 0 fail (matches tests/expected-counts.json); bun test:bun smoke PASS (8/8). --- src/controllers/anthropic.js | 12 ++++-------- tests/tool-prompt.test.js | 6 +++++- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/controllers/anthropic.js b/src/controllers/anthropic.js index d1f6344c..186300ac 100644 --- a/src/controllers/anthropic.js +++ b/src/controllers/anthropic.js @@ -1262,8 +1262,6 @@ const handleAnthropicStream = async (res, ctx, upstream) => { let textBlockOpen = false; let thinkingBlockOpen = false; let thinkingSignature = null; - let promptTokens = 0; - let completionTokens = 0; let upstreamUsage = null; // 上游逐帧累计的 usage(DashScope 命名已归一化;null = 还没报) let upstreamFinishReason = null; let upstreamCompleted; @@ -2001,8 +1999,8 @@ const handleAnthropicStream = async (res, ctx, upstream) => { // 只对上游没报的字段补本地估算(早停的回合收不到尾部 usage 帧) const usage = reportUsage(upstreamUsage, () => createUsageObject(requestBody?.messages || '', completionContent), 'ANTHROPIC'); - promptTokens = usage.prompt_tokens; - completionTokens = usage.completion_tokens; + const promptTokens = usage.prompt_tokens; + const completionTokens = usage.completion_tokens; // Daily stats 累计——一次性归属主账户(见模块顶部 attributeChatUsage 注释) attributeChatUsage(ctx.currentAccount, promptTokens, completionTokens); @@ -2041,8 +2039,6 @@ const handleAnthropicNonStream = async (res, ctx, upstream) => { // 与流式分支同一条纪律,上一轮的泄漏已经重试过了。 let attemptThinkingContent = ''; let answerContent = ''; - let promptTokens = 0; - let completionTokens = 0; let upstreamUsage = null; // 上游逐帧累计的 usage(DashScope 命名已归一化;null = 还没报) let webSearchInfo = null; let upstreamFinishReason = null; @@ -2577,8 +2573,8 @@ const handleAnthropicNonStream = async (res, ctx, upstream) => { const nativeArgsText = nativeToolCalls.map(call => call.function.arguments || '').join(''); return createUsageObject(requestBody?.messages || '', thinkingContent + answerContent + nativeArgsText); }, 'ANTHROPIC'); - promptTokens = usage.prompt_tokens; - completionTokens = usage.completion_tokens; + const promptTokens = usage.prompt_tokens; + const completionTokens = usage.completion_tokens; const contentBlocks = []; if (thinkingContent && thinkingContent.trim()) { diff --git a/tests/tool-prompt.test.js b/tests/tool-prompt.test.js index 695fef0e..333e5986 100644 --- a/tests/tool-prompt.test.js +++ b/tests/tool-prompt.test.js @@ -816,7 +816,11 @@ test('lockstep: ningun sitio de prompt/hint re-ensena la forma nativa line.replace(/\/\/.*$/, '')) + // Bounded by the newline, not by `$`: on a CRLF checkout `$` matches before + // the CR, so `.*` backtracked to the CR and left the comment body in `code` + // — the rationale comments that legitimately name `` then failed + // the scan below. + .map(line => line.replace(/\/\/[^\r\n]*/, '')) .join('\n') assert.doesNotMatch(code, /<[ \t]*\/?[ \t]*tool_call[ >]/i, `${rel}: cadena con la forma nativa legible por el modelo`) }