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

- 只翻注释/文档字符串,代码零变化:go/scanner 词法流比对 21 文件 token+字面量全等,增删行数 1:1(467/467)
- 刻意保留非散文英文:JSON Schema description、工具 Description() 返回值、adapter prompt、API 路径与命令示例、环境变量名
- 逐行确认代码前缀未变,未触碰其他模块
This commit is contained in:
AskaEth committed 2026-10-04 12:28:16 +08:00
1 parent b9e042d07d
commit b0fbb8bc0d
21 files changed
+467 -467

No files matched your search

+28 -28
View File
@@ -7,31 +7,31 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
)
// ModelInfoProvider supplies the main model's vision capability so the resolver
// can route an image the way the vision Router decides (design/06 §0). It is
// called per image; the same provider is shared across a single resolution.
// ModelInfoProvider 提供主模型的视觉能力,使解析器
// 能按 vision Router 的判定(design/06 §0)路由图像。它按
// 图像逐个调用;同一次解析中共享同一个 provider。
type ModelInfoProvider func() ModelInfo
// ToolInvoker invokes a registered tool (the vision or OCR tool) by name with
// the given arguments. It is satisfied by *tool.Dispatcher.Invoke.
// ToolInvoker 按名字与给定参数调用一个已注册的工具(视觉或 OCR
// 工具)。由 *tool.Dispatcher.Invoke 满足。
type ToolInvoker func(ctx context.Context, name string, args map[string]any) (any, error)
// MessageResolver is the loop's concrete ImageResolver. For each image part in a
// user message it asks the vision Router how to route it: when the main model
// supports vision and is confident, the image part is kept so the main model sees
// the image; otherwise the vision/OCR tool is invoked and its text result replaces
// the image part, so a text-only main model can reason over the image ("先看图再
// 对话"). It is safe for concurrent use.
// MessageResolver 是 loop 的具体 ImageResolver。对用户消息中的
// 每个图像部件,它向 vision Router 询问如何路由:当主模型
// 支持视觉且有信心时,保留该图像部件让主模型看到
// 图像;否则调用 vision/OCR 工具,用其文字结果替换
// 图像部件,使纯文本主模型也能对图像推理(「先看图再
// 对话」)。它可安全并发使用。
type MessageResolver struct {
router *Router
info ModelInfoProvider
invoke ToolInvoker
}
// NewMessageResolver builds a MessageResolver. router decides the layer; info
// reports the main model's vision capability; invoke runs a registered vision/OCR
// tool. A nil invoke leaves any tool route failed (the image is then kept), so a
// resolver without tools degrades to the main-model path.
// NewMessageResolver 构造一个 MessageResolver。router 决定
// 分层;info 报告主模型的视觉能力;invoke 运行一个已注册的 vision/OCR
// 工具。invoke 为 nil 时任何工具路由都会失败(此时图像被保留),
// 因此没有工具的解析器会降级到主模型路径。
func NewMessageResolver(router *Router, info ModelInfoProvider, invoke ToolInvoker) *MessageResolver {
return &MessageResolver{
router: router,
@@ -40,10 +40,10 @@ func NewMessageResolver(router *Router, info ModelInfoProvider, invoke ToolInvok
}
}
// Resolve rewrites msg so every image part is either kept (main model sees it) or
// replaced by a text description produced by the vision/OCR tool. Text parts are
// preserved in order. It errors only when an image cannot be routed or a tool
// invocation fails; the caller (loop) then keeps the original message.
// Resolve 改写 msg,使每个图像部件要么被保留(主模型能看到它),
// 要么被 vision/OCR 工具产出的文字描述替换。文本部件
// 按原顺序保留。它仅在图像无法路由或工具
// 调用失败时报错;此时调用方(loop)保留原始消息。
func (r *MessageResolver) Resolve(ctx context.Context, msg model.Message) (model.Message, error) {
if r.router == nil {
return msg, nil
@@ -63,8 +63,8 @@ func (r *MessageResolver) Resolve(ctx context.Context, msg model.Message) (model
return model.Message{Role: msg.Role, Content: out}, nil
}
// resolveImage picks a route and either keeps the image (KindMain) or folds it
// into a text description via the vision/OCR tool.
// resolveImage 选出一条路由:要么保留图像(KindMain),
// 要么经 vision/OCR 工具把它折叠为文字描述。
func (r *MessageResolver) resolveImage(ctx context.Context, imageURL string) (model.Content, error) {
target := ModelInfo{}
if r.info != nil {
@@ -73,7 +73,7 @@ func (r *MessageResolver) resolveImage(ctx context.Context, imageURL string) (mo
decision := r.router.Route(target, RouteRequest{})
switch decision.Kind {
case KindMain:
// A vision-capable main model sees the image directly.
// 支持视觉的主模型直接看到这张图。
return model.Content{Type: model.ContentTypeImage, ImageURL: imageURL}, nil
case KindVisionTool:
return r.invokeTool(ctx, decision.Tool, map[string]any{
@@ -89,8 +89,8 @@ func (r *MessageResolver) resolveImage(ctx context.Context, imageURL string) (mo
}
}
// invokeTool runs a registered vision/OCR tool and turns its text result into a
// text content part. field is the result map key ("description" or "text").
// invokeTool 运行一个已注册的 vision/OCR 工具,并把其文字结果转成
// 文本内容部件。field 是结果 map 的键("description" 或 "text")。
func (r *MessageResolver) invokeTool(ctx context.Context, toolName string, args map[string]any, field string) (model.Content, error) {
if r.invoke == nil {
return model.Content{}, fmt.Errorf("%s: %w", toolName, ErrNotConfigured)
@@ -102,8 +102,8 @@ func (r *MessageResolver) invokeTool(ctx context.Context, toolName string, args
return model.Content{Type: model.ContentTypeText, Text: descriptionFragment(fieldText(result, field))}, nil
}
// fieldText extracts a string field from a tool result map, tolerating the
// map[string]any shape returned by the vision/OCR tools.
// fieldText 从工具结果的 map 中取出字符串字段,兼容
// vision/OCR 工具返回的 map[string]any 形状。
func fieldText(result any, field string) string {
m, ok := result.(map[string]any)
if !ok {
@@ -113,8 +113,8 @@ func fieldText(result any, field string) string {
return s
}
// descriptionFragment labels a tool-produced description so the model can tell it
// refers to the picture the user attached.
// descriptionFragment 给工具产出的描述加上标注,使模型能看出它
// 指的是用户附上的那张图。
func descriptionFragment(desc string) string {
if desc == "" {
return "[图片内容] 无法识别该图片"