- 只翻注释/文档字符串:`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
80 lines
2.7 KiB
Go
80 lines
2.7 KiB
Go
package model
|
||
|
||
import (
|
||
"encoding/json"
|
||
)
|
||
|
||
// openAIChatResponse 是 /chat/completions 返回的 JSON 体,既用于
|
||
// 非流式负载,也用于每个 SSE 流块。
|
||
type openAIChatResponse struct {
|
||
ID string `json:"id"`
|
||
Model string `json:"model"`
|
||
Choices []openAIChoice `json:"choices"`
|
||
Usage *openAIUsage `json:"usage,omitempty"`
|
||
}
|
||
|
||
// openAIChoice 是一个候选补全。
|
||
type openAIChoice struct {
|
||
Index int `json:"index"`
|
||
Message openAIResponseMessage `json:"message"`
|
||
Delta *openAIDelta `json:"delta,omitempty"`
|
||
FinishReason string `json:"finish_reason,omitempty"`
|
||
}
|
||
|
||
// openAIResponseMessage 是非流式 choice 里的助手消息。
|
||
type openAIResponseMessage struct {
|
||
Role string `json:"role"`
|
||
Content string `json:"content"`
|
||
ToolCalls []openAIToolCall `json:"tool_calls,omitempty"`
|
||
}
|
||
|
||
// openAIDelta 是流块里的增量负载。推理内容
|
||
// (OpenAI o 系 / DeepSeek / DashScope)到达 ReasoningContent;流式
|
||
// 函数调用到达 ToolCalls,按片段索引累积。
|
||
type openAIDelta struct {
|
||
Role string `json:"role"`
|
||
Content string `json:"content"`
|
||
ReasoningContent string `json:"reasoning_content"`
|
||
ToolCalls []openAIToolCallDelta `json:"tool_calls"`
|
||
}
|
||
|
||
// openAIToolCallDelta 是一个流式函数调用片段。OpenAI 会发出一串
|
||
// 共享同一 Index 的此类片段:ID 与 Function.Name 通常
|
||
// 只在第一个片段里出现一次,而 Function.Arguments 跨
|
||
// 多个片段流式到达。
|
||
type openAIToolCallDelta struct {
|
||
Index int `json:"index"`
|
||
ID string `json:"id"`
|
||
Function openAIToolCallFn `json:"function"`
|
||
}
|
||
|
||
// openAIUsage 上报 token 消耗。
|
||
type openAIUsage struct {
|
||
PromptTokens int `json:"prompt_tokens"`
|
||
CompletionTokens int `json:"completion_tokens"`
|
||
TotalTokens int `json:"total_tokens"`
|
||
}
|
||
|
||
func responseFromWire(wire *openAIChatResponse) Response {
|
||
out := Response{Model: wire.Model}
|
||
if len(wire.Choices) > 0 {
|
||
text := wire.Choices[0].Message.Content
|
||
out.Content = text
|
||
out.Message = Message{Role: RoleAssistant, Content: []Content{{Type: ContentTypeText, Text: text}}}
|
||
out.StopReason = wire.Choices[0].FinishReason
|
||
for _, tc := range wire.Choices[0].Message.ToolCalls {
|
||
args := map[string]any{}
|
||
if tc.Function.Arguments != "" {
|
||
_ = json.Unmarshal([]byte(tc.Function.Arguments), &args)
|
||
}
|
||
out.ToolCalls = append(out.ToolCalls, ToolCall{Name: tc.Function.Name, ID: tc.ID, Args: args})
|
||
}
|
||
}
|
||
if u := wire.Usage; u != nil {
|
||
out.PromptTokens = u.PromptTokens
|
||
out.CompletionTokens = u.CompletionTokens
|
||
out.TotalTokens = u.TotalTokens
|
||
}
|
||
return out
|
||
}
|