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
@@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// openAIChatRequest is the JSON body sent to /chat/completions. Field names
|
||||
// match the provider protocol so the struct marshals directly.
|
||||
// openAIChatRequest 是发给 /chat/completions 的 JSON 请求体。字段名
|
||||
// 与提供商协议一致,因此该结构体可以直接序列化。
|
||||
type openAIChatRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []openAIMessage `json:"messages"`
|
||||
@@ -15,49 +15,49 @@ type openAIChatRequest struct {
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *openAIStreamOpts `json:"stream_options,omitempty"`
|
||||
Tools []openAITool `json:"tools,omitempty"`
|
||||
// Thinking is DeepSeek's top-level thinking switch. It is sent only for
|
||||
// DeepSeek and only from an explicit switch (or an explicit off that must be
|
||||
// honoured): leaving it out keeps the provider default, which is ENABLED, so
|
||||
// an omitted field is not a way to switch thinking off (design/04 §3.2
|
||||
// fact 2).
|
||||
// Thinking 是 DeepSeek 的顶层思考开关。它只对
|
||||
// DeepSeek 发送,且只在有显式开关(或必须被
|
||||
// 尊重的显式关闭)时发送:省略它会保留提供商默认值,而该默认值
|
||||
// 是「开启」,所以省略字段并不是关闭思考的办法(design/04 §3.2
|
||||
// 事实 2)。
|
||||
Thinking *openAIThinking `json:"thinking,omitempty"`
|
||||
// ReasoningEffort is the OpenAI-compatible reasoning strength knob. It is set
|
||||
// only after validation against the detected vendor's whitelist (design/04
|
||||
// §3.2); an unrecognized value is dropped, never turned into a different tier.
|
||||
// ReasoningEffort 是 OpenAI 兼容的推理强度旋钮。它只在
|
||||
// 对已识别厂商的白名单校验通过后才设置(design/04
|
||||
// §3.2);无法识别的值会被丢弃,绝不会被换成别的档位。
|
||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||
// ChatTemplateKwargs carries the vLLM-style thinking switch
|
||||
// (chat_template_kwargs.enable_thinking, design/04 §3.2 Qwen3 行). It is sent
|
||||
// only to an endpoint whose provider declared reasoning.kind=vllm.
|
||||
// ChatTemplateKwargs 承载 vLLM 风格的思考开关
|
||||
// (chat_template_kwargs.enable_thinking,design/04 §3.2 Qwen3 行)。它只
|
||||
// 发送给提供商声明了 reasoning.kind=vllm 的端点。
|
||||
ChatTemplateKwargs *openAIChatTemplateKwargs `json:"chat_template_kwargs,omitempty"`
|
||||
// EnableThinking carries the DashScope compatible-mode thinking switch (the
|
||||
// top-level enable_thinking). It is sent only to an endpoint whose provider
|
||||
// declared reasoning.kind=dashscope — the shape is never inferred, because a
|
||||
// wrong shape 400s the request.
|
||||
// EnableThinking 承载 DashScope 兼容模式的思考开关(
|
||||
// 顶层 enable_thinking)。它只发送给提供商
|
||||
// 声明了 reasoning.kind=dashscope 的端点——该形状永不推断,因为
|
||||
// 形状错了会让请求 400。
|
||||
EnableThinking *bool `json:"enable_thinking,omitempty"`
|
||||
}
|
||||
|
||||
// openAIThinking is the wire form of DeepSeek's thinking switch: enabled or
|
||||
// disabled. It is only ever sent to a DeepSeek endpoint.
|
||||
// openAIThinking 是 DeepSeek 思考开关的线格式:enabled 或
|
||||
// disabled。它只会发给 DeepSeek 端点。
|
||||
type openAIThinking struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// openAIChatTemplateKwargs is the wire form of the vLLM (Qwen3) thinking switch:
|
||||
// the boolean lives nested under chat_template_kwargs.
|
||||
// openAIChatTemplateKwargs 是 vLLM(Qwen3)思考开关的线格式:
|
||||
// 该布尔值嵌在 chat_template_kwargs 之下。
|
||||
type openAIChatTemplateKwargs struct {
|
||||
EnableThinking *bool `json:"enable_thinking,omitempty"`
|
||||
}
|
||||
|
||||
// openAIStreamOpts asks the provider to include usage in the final stream chunk.
|
||||
// openAIStreamOpts 请求提供商在最后一个流块里带上用量。
|
||||
type openAIStreamOpts struct {
|
||||
IncludeUsage bool `json:"include_usage"`
|
||||
}
|
||||
|
||||
// openAIMessage is one request message in the wire body. Content is either a
|
||||
// plain string (text-only) or an array of {type,text|image_url} parts. Tool
|
||||
// messages carry ToolCallID (required by OpenAI); assistant messages that
|
||||
// requested functions carry ToolCalls so the following tool messages can be
|
||||
// correlated.
|
||||
// openAIMessage 是线格式请求体里的一条消息。Content 要么是
|
||||
// 纯字符串(仅文本),要么是 {type,text|image_url} 片段数组。Tool
|
||||
// 消息携带 ToolCallID(OpenAI 要求);请求过函数的助手消息
|
||||
// 携带 ToolCalls,以便随后的 tool 消息能够
|
||||
// 被关联。
|
||||
type openAIMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content any `json:"content"`
|
||||
@@ -65,28 +65,28 @@ type openAIMessage struct {
|
||||
ToolCalls []openAIToolCall `json:"tool_calls,omitempty"`
|
||||
}
|
||||
|
||||
// openAIToolCall is the wire form of one assistant tool_call in a request. OpenAI
|
||||
// requires each subsequent tool message to reference the id back to these calls.
|
||||
// openAIToolCall 是请求里单个助手 tool_call 的线格式。OpenAI
|
||||
// 要求每条后续 tool 消息都把这些调用的 id 引用回来。
|
||||
type openAIToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Function openAIToolCallFn `json:"function"`
|
||||
}
|
||||
|
||||
// openAITool is the wire form of a function tool schema (M2 placeholder).
|
||||
// openAITool 是函数工具 schema 的线格式(M2 占位)。
|
||||
type openAITool struct {
|
||||
Type string `json:"type"`
|
||||
Function openAIToolFn `json:"function"`
|
||||
}
|
||||
|
||||
// openAIToolFn carries the function definition.
|
||||
// openAIToolFn 承载函数定义。
|
||||
type openAIToolFn struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Parameters any `json:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
// openAIToolCallFn is the function part of a streaming tool-call fragment.
|
||||
// openAIToolCallFn 是流式工具调用片段的函数部分。
|
||||
type openAIToolCallFn struct {
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments"`
|
||||
@@ -97,12 +97,12 @@ func (a *OpenAIChatAdapter) buildRequest(req Request, stream bool) ([]byte, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// The vendor behind an OpenAI-compatible endpoint decides which
|
||||
// reasoning_effort tiers are legal and whether it has a thinking switch;
|
||||
// classify it from the resolved model (and the base URL as a fallback) before
|
||||
// touching the request. The endpoint's configured shape (models.json
|
||||
// reasoning.kind, 裁决 03.4.2/08.4.1) wins over that classification, because
|
||||
// the same wire protocol carries different switch shapes (vLLM vs DashScope).
|
||||
// OpenAI 兼容端点背后的厂商决定哪些
|
||||
// reasoning_effort 档位合法、以及它是否有思考开关;
|
||||
// 在改动请求之前,先按已解析出的模型(并以 base URL 作降级)
|
||||
// 分类。端点已声明的形状(models.json
|
||||
// 的 reasoning.kind,裁决 03.4.2/08.4.1)优先于该分类,因为
|
||||
// 同一线协议承载着不同的开关形状(vLLM 对 DashScope)。
|
||||
vendor := reasoningVendorFor(req.Model, a.baseURL)
|
||||
plan := resolveOpenAIReasoning(a.log, a.reasoningKind, vendor, req.Model, req.Thinking, req.ReasoningEffort)
|
||||
reportForcedToolChoiceWithThinking(a.log, plan.provider, req.Model, req.ToolChoice, plan.thinkingOn())
|
||||
@@ -140,10 +140,10 @@ func buildMessages(msgs []Message) ([]openAIMessage, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// encodeOpenAIMessage renders one normalized message in OpenAI wire form. A
|
||||
// RoleTool turn becomes a tool message carrying tool_call_id (required by OpenAI,
|
||||
// and the audit's gap); an assistant turn that advertised tool calls carries the
|
||||
// corresponding tool_calls array so the provider can correlate the tool messages.
|
||||
// encodeOpenAIMessage 把一条归一化消息渲染成 OpenAI 线格式。
|
||||
// RoleTool 回合变成携带 tool_call_id 的 tool 消息(OpenAI 要求,
|
||||
// 也是审计指出的缺口);声明过工具调用的助手回合携带
|
||||
// 对应的 tool_calls 数组,好让提供商能关联 tool 消息。
|
||||
func encodeOpenAIMessage(m Message) (openAIMessage, error) {
|
||||
if m.Role == RoleTool {
|
||||
return openAIMessage{
|
||||
@@ -159,8 +159,8 @@ func encodeOpenAIMessage(m Message) (openAIMessage, error) {
|
||||
return openAIMessage{Role: string(m.Role), Content: content, ToolCalls: encodeToolCalls(m.Content)}, nil
|
||||
}
|
||||
|
||||
// toolMessageCallID resolves the tool_call_id for a RoleTool turn: the
|
||||
// message-level id, else the id carried on the first tool-result part.
|
||||
// toolMessageCallID 解出 RoleTool 回合的 tool_call_id:
|
||||
// 先是消息级 id,否则取第一个工具结果片段上的 id。
|
||||
func toolMessageCallID(m Message) string {
|
||||
if m.ToolCallID != "" {
|
||||
return m.ToolCallID
|
||||
@@ -173,8 +173,8 @@ func toolMessageCallID(m Message) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// encodeToolCalls builds the assistant tool_calls array from a turn's tool-call
|
||||
// parts. Arguments are serialized to JSON because OpenAI expects a string.
|
||||
// encodeToolCalls 由回合的工具调用片段构建助手的 tool_calls
|
||||
// 数组。参数序列化为 JSON,因为 OpenAI 期望字符串。
|
||||
func encodeToolCalls(parts []Content) []openAIToolCall {
|
||||
calls := make([]openAIToolCall, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
@@ -211,8 +211,8 @@ func encodeContent(parts []Content) (any, error) {
|
||||
"image_url": map[string]any{"url": p.ImageURL},
|
||||
})
|
||||
case ContentTypeToolCall, ContentTypeToolResult:
|
||||
// Tool-call and tool-result parts are encoded at the message level
|
||||
// (tool_calls array / tool_call_id), never as text-image content.
|
||||
// 工具调用与工具结果片段在消息级编码
|
||||
// (tool_calls 数组 / tool_call_id),绝不作为文本-图片内容。
|
||||
continue
|
||||
default:
|
||||
return nil, fmt.Errorf("model: %w: unsupported content type %q", ErrBadRequest, p.Type)
|
||||
|
||||
Reference in new issue
Block a user