feat: AutoZero 通用 Agent 框架(从 AutoGo 五阶段拆分完成)
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。
This commit is contained in:
commit
d5dac5a6fc
140 files changed
+26497
No files matched your search
+114
@@ -0,0 +1,114 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/jpeg"
|
||||
_ "image/png" // 解码 PNG 截图
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 视觉压缩策略:视觉模型会把图片缩到 ~1568px 再处理,原始 Retina 全屏 PNG
|
||||
// (2-3MB)纯属浪费且容易顶爆网关的单请求字节上限。超过阈值就降采样到
|
||||
// maxVisionWidth 并转 JPEG(截图场景质量足够,体积约 1/10)。
|
||||
const (
|
||||
shrinkThresholdBytes = 600 << 10 // 600KB
|
||||
maxVisionWidth = 1280
|
||||
visionJPEGQuality = 80
|
||||
)
|
||||
|
||||
// ShrinkForVision 尽力压缩大图:PNG 且超过阈值时降采样 + 转 JPEG,
|
||||
// 返回新路径;小图或解码失败时原样返回(调用方无需关心错误)。
|
||||
func ShrinkForVision(path string) (string, error) {
|
||||
st, err := os.Stat(path)
|
||||
if err != nil || st.Size() <= shrinkThresholdBytes {
|
||||
return path, nil
|
||||
}
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return path, nil
|
||||
}
|
||||
src, _, err := image.Decode(f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return path, nil // 非图片/损坏:保持原样
|
||||
}
|
||||
|
||||
scaled := scaleToWidth(src, maxVisionWidth)
|
||||
out := fmt.Sprintf("%s/vision-%d.jpg", os.TempDir(), time.Now().UnixNano())
|
||||
of, err := os.Create(out)
|
||||
if err != nil {
|
||||
return path, nil
|
||||
}
|
||||
if err := jpeg.Encode(of, scaled, &jpeg.Options{Quality: visionJPEGQuality}); err != nil {
|
||||
of.Close()
|
||||
os.Remove(out)
|
||||
return path, nil
|
||||
}
|
||||
if err := of.Close(); err != nil {
|
||||
os.Remove(out)
|
||||
return path, nil
|
||||
}
|
||||
// 压缩后反而更大(异常情况)则回退原图
|
||||
if ost, err2 := os.Stat(out); err2 != nil || ost.Size() >= st.Size() {
|
||||
os.Remove(out)
|
||||
return path, nil
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// scaleToWidth 等比缩到 maxW 宽(box 平均采样,stdlib 实现)。
|
||||
func scaleToWidth(src image.Image, maxW int) image.Image {
|
||||
b := src.Bounds()
|
||||
w, h := b.Dx(), b.Dy()
|
||||
if w <= maxW || w == 0 || h == 0 {
|
||||
return src
|
||||
}
|
||||
nh := h * maxW / w
|
||||
if nh < 1 {
|
||||
nh = 1
|
||||
}
|
||||
dst := image.NewRGBA(image.Rect(0, 0, maxW, nh))
|
||||
for y := 0; y < nh; y++ {
|
||||
sy0, sy1 := y*h/nh, (y+1)*h/nh
|
||||
if sy1 <= sy0 {
|
||||
sy1 = sy0 + 1
|
||||
}
|
||||
for x := 0; x < maxW; x++ {
|
||||
sx0, sx1 := x*w/maxW, (x+1)*w/maxW
|
||||
if sx1 <= sx0 {
|
||||
sx1 = sx0 + 1
|
||||
}
|
||||
var rs, gs, bs, as, n uint64
|
||||
stepY := (sy1 - sy0) / 4
|
||||
if stepY < 1 {
|
||||
stepY = 1
|
||||
}
|
||||
stepX := (sx1 - sx0) / 4
|
||||
if stepX < 1 {
|
||||
stepX = 1
|
||||
}
|
||||
for sy := sy0; sy < sy1; sy += stepY {
|
||||
for sx := sx0; sx < sx1; sx += stepX {
|
||||
r, g, bl, a := src.At(b.Min.X+sx, b.Min.Y+sy).RGBA()
|
||||
rs += uint64(r)
|
||||
gs += uint64(g)
|
||||
bs += uint64(bl)
|
||||
as += uint64(a)
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
n = 1
|
||||
}
|
||||
dst.Set(x, y, rgbaFrom64(rs/n, gs/n, bs/n, as/n))
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func rgbaFrom64(r, g, b, a uint64) color.RGBA {
|
||||
return color.RGBA{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: uint8(a >> 8)}
|
||||
}
|
||||
Reference in new issue
Block a user