llm(三协议 Provider)/ session(JSONL 持久化)/ tools(Registry、围栏、 builtin、computer)/ cdp(browser)/ skills / mcp / agent(循环、两级压缩、 编排、审批门控)+ 底座 jsonl/textx/execx/diag/scratch/spill/imagecache。 产品装配代码(config 桥接、schedule 工具、memory/plan/retro/prompt) 留在 AutoGo,宿主接入方式见 MIGRATION.md。
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package llm
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
var mediaTypes = map[string]string{
|
|
".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
|
|
".gif": "image/gif", ".webp": "image/webp",
|
|
}
|
|
|
|
// maxImageBytes 限制单张图大小,避免一次请求爆掉 token/体积。
|
|
const maxImageBytes = 8 << 20
|
|
|
|
// LoadImage 读图并 base64 编码,返回 (b64, mediaType)。
|
|
func LoadImage(path string) (string, string, error) {
|
|
ext := strings.ToLower(filepath.Ext(path))
|
|
mt, ok := mediaTypes[ext]
|
|
if !ok {
|
|
return "", "", fmt.Errorf("unsupported image type %q", ext)
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
if len(data) > maxImageBytes {
|
|
return "", "", fmt.Errorf("image too large: %d bytes (limit %d)", len(data), maxImageBytes)
|
|
}
|
|
return base64.StdEncoding.EncodeToString(data), mt, nil
|
|
}
|
|
|
|
// ImageEstimateTokens 是单张图在 token 粗估中的保守常数(1080p 截图约 1.1-1.6k tokens)。
|
|
const ImageEstimateTokens = 1400
|
|
|
|
// loadImageRef 统一解析图片引用:Filename 走缓存(优先),Path 直读(兼容旧格式)。
|
|
func loadImageRef(img Image) (b64, mime string, err error) {
|
|
if img.Filename != "" && imageCache != nil {
|
|
return imageCache.LoadWithMIME(img.Filename)
|
|
}
|
|
if img.Path != "" {
|
|
return LoadImage(img.Path)
|
|
}
|
|
return "", "", fmt.Errorf("no image path or filename provided")
|
|
}
|
|
|
|
// imageUnavailable 文本占位(图片读取失败时各 provider 的统一降级文案)。
|
|
func imageUnavailable(img Image, err error) string {
|
|
ref := img.Path
|
|
if img.Filename != "" {
|
|
ref = img.Filename
|
|
}
|
|
return "[image unavailable: " + ref + ": " + err.Error() + "]"
|
|
}
|