docs(comments): 注释中文化 · internal/runtime/model + internal/services/backthink(54 文件,纯替换)
- 只翻注释/文档字符串:`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:
1 parent
f5cf117482
commit
3dc1232bc2
54 files changed
+1923
-1923
No files matched your search
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user