docs(comments): 注释中文化 · internal/runtime/model + internal/services/backthink(54 文件,纯替换)
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 只翻注释/文档字符串:`go/scanner` 剥注释后按 token 序列+literal 逐 token 比对,**54/54 文件 SAME**;
  改动文件总行数与 HEAD 漂移 = 0(严格 1:1,无合并/拆行)
- 裁决编号与 design 节号逐字保留(03.4.1/03.4.2/03.4.3/14.4.1/14.4.5/07.4.2-4、design/04 §3.1/§3.2 等);
  `chat_template_kwargs` / `enable_thinking` / `reasoning_effort` / `thinking:{type}` 字段名与形状说明未动
- 存疑译法(已登记):`persona` 在叙事语境用「角色」、标识符语境保留 `persona`(仓库既有模块本身混用);
  `rung`→「级」;`provider` 存在「提供商/提供者」两种落笔(可按需一键统一)
- 复核:build/vet 绿 + 两包测试绿;gofmt 干净;残留英文注释 0 条
- 既有存量(未修,只报告):`model/anthropic_test.go` 612 行 >500;`applyAnthropicEvent` 115 行 >80
This commit is contained in:
AskaEth committed 2026-10-04 16:27:54 +08:00
1 parent f5cf117482
commit 3dc1232bc2
54 files changed
+1923 -1923

No files matched your search

+27 -27
View File
@@ -14,9 +14,9 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
)
// anthropicSeqServer answers successive /v1/messages calls with a fixed script
// of bodies (the last body repeats) and records every decoded request body, so a
// test can assert both the retry count and the retried max_tokens.
// anthropicSeqServer 用一份固定的响应体脚本回答连续的 /v1/messages
// 调用(最后一个响应体重复),并记录每个已解码的请求体,因此
// 测试既能断言重试次数、也能断言重试后的 max_tokens。
type anthropicSeqServer struct {
*httptest.Server
mu sync.Mutex
@@ -61,8 +61,8 @@ func (s *anthropicSeqServer) body(i int) map[string]any {
return s.bodies[i]
}
// anthropicThinkingOnlyResponse is a thinking-only, budget-truncated reply: the
// reasoning consumed the whole max_tokens budget, so no text block was emitted.
// anthropicThinkingOnlyResponse 是一份只有思考、被预算截断的回复:
// 推理吃光了整个 max_tokens 预算,所以没有文本块被发出。
const anthropicThinkingOnlyResponse = `{
"id":"msg_think","model":"claude-test",
"content":[{"type":"thinking","thinking":"SECRET-REASONING long long long"}],
@@ -84,8 +84,8 @@ const anthropicToolUseResponse = `{
"usage":{"input_tokens":5,"output_tokens":8}
}`
// anthropicTruncatedThinkingSSE is the streaming form of a thinking-only
// truncation: a thinking block, then message_delta stop_reason max_tokens.
// anthropicTruncatedThinkingSSE 是「只有思考」截断的流式形态:
// 一个 thinking 块,随后是 message_delta 的 stop_reason max_tokens。
const anthropicTruncatedThinkingSSE = `data: {"type":"message_start","message":{"model":"claude-test","usage":{"input_tokens":5}}}
data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":""}}
@@ -114,9 +114,9 @@ data: {"type":"message_stop"}
`
// TestAnthropicChat_TruncatedThinking_RetriesWithDoubledBudget proves the
// primary recovery: a max_tokens truncation with only a thinking block retries
// exactly once with the token budget doubled and surfaces the retry's text.
// TestAnthropicChat_TruncatedThinking_RetriesWithDoubledBudget 证明
// 主恢复路径:只有 thinking 块的 max_tokens 截断会
// 恰好重试一次、token 预算翻倍,并浮出重试的文本。
func TestAnthropicChat_TruncatedThinking_RetriesWithDoubledBudget(t *testing.T) {
t.Parallel()
srv := newAnthropicSeqServer(t, "application/json", anthropicThinkingOnlyResponse, anthropicEndTurnTextResponse)
@@ -149,9 +149,9 @@ func TestAnthropicChat_TruncatedThinking_RetriesWithDoubledBudget(t *testing.T)
}
}
// TestAnthropicChat_TruncatedThinking_RetryStillEmpty_FallsBackToHint proves the
// safety net: when the retry is truncated too, the caller gets a non-empty
// placeholder instead of a silent empty reply, and the thinking never leaks.
// TestAnthropicChat_TruncatedThinking_RetryStillEmpty_FallsBackToHint 证明
// 兜底网:连重试也被截断时,调用方拿到非空
// 占位,而不是静默空回复,且思考永不泄漏。
func TestAnthropicChat_TruncatedThinking_RetryStillEmpty_FallsBackToHint(t *testing.T) {
t.Parallel()
srv := newAnthropicSeqServer(t, "application/json", anthropicThinkingOnlyResponse, anthropicThinkingOnlyResponse)
@@ -184,9 +184,9 @@ func TestAnthropicChat_TruncatedThinking_RetryStillEmpty_FallsBackToHint(t *test
}
}
// TestAnthropicChat_NormalStop_NoRetry proves a normal end_turn answer and a
// native tool_use round (whose body is legitimately empty) are left untouched:
// no retry, no fallback hint.
// TestAnthropicChat_NormalStop_NoRetry 证明正常的 end_turn 答复与
// 原生 tool_use 回合(其正文合法地为空)保持不动:
// 不重试、不补兜底占位。
func TestAnthropicChat_NormalStop_NoRetry(t *testing.T) {
t.Parallel()
t.Run("end_turn", func(t *testing.T) {
@@ -224,9 +224,9 @@ func TestAnthropicChat_NormalStop_NoRetry(t *testing.T) {
})
}
// TestAnthropicChatStream_TruncatedThinking_RetriesWithDoubledBudget proves the
// streaming retry: the retry's thinking is suppressed (no duplicate block) while
// its text streams through, and the doubled budget is sent.
// TestAnthropicChatStream_TruncatedThinking_RetriesWithDoubledBudget 证明
// 流式重试:重试产生的思考被抑制(无重复块),
// 而其文本流过,且发送的是翻倍预算。
func TestAnthropicChatStream_TruncatedThinking_RetriesWithDoubledBudget(t *testing.T) {
t.Parallel()
srv := newAnthropicSeqServer(t, "text/event-stream", anthropicTruncatedThinkingSSE, anthropicEndTurnTextSSE)
@@ -265,10 +265,10 @@ func TestAnthropicChatStream_TruncatedThinking_RetriesWithDoubledBudget(t *testi
}
}
// TestAnthropicChatStream_TruncatedThinking_RetryStillEmpty_EmitsHint proves the
// streaming safety net: when the retry is truncated too, a non-empty placeholder
// is emitted as a text segment (and returned as the body) so the frontend is not
// left with a silent truncated turn.
// TestAnthropicChatStream_TruncatedThinking_RetryStillEmpty_EmitsHint 证明
// 流式兜底网:连重试也被截断时,会以文本片段发出非空
// 占位(并把它作为正文返回),因此前端不会
// 停在一个静默截断的回合上。
func TestAnthropicChatStream_TruncatedThinking_RetryStillEmpty_EmitsHint(t *testing.T) {
t.Parallel()
srv := newAnthropicSeqServer(t, "text/event-stream", anthropicTruncatedThinkingSSE, anthropicTruncatedThinkingSSE)
@@ -301,7 +301,7 @@ func TestAnthropicChatStream_TruncatedThinking_RetryStillEmpty_EmitsHint(t *test
}
}
// TestTruncationBudget covers the budget arithmetic that bounds the retry.
// TestTruncationBudget 覆盖约束重试的预算算术。
func TestTruncationBudget(t *testing.T) {
t.Parallel()
cases := []struct {
@@ -328,9 +328,9 @@ func TestTruncationBudget(t *testing.T) {
}
}
// TestOpenAIChat_StopReasonMapping asserts the OpenAI adapter fills the unified
// Response.StopReason from finish_reason on both the non-streaming and streaming
// paths, so a "length" truncation is identifiable across protocols.
// TestOpenAIChat_StopReasonMapping 断言 OpenAI 适配器在非流式与
// 流式两条路径上都由 finish_reason 填充统一的
// Response.StopReason,因此 "length" 截断在各协议间都可识别。
func TestOpenAIChat_StopReasonMapping(t *testing.T) {
t.Parallel()
t.Run("non_streaming", func(t *testing.T) {