feat: v2.3.0 流式输出 + 日志系统 + 会议室架构全面升级
- 流式输出: SSE 逐 token 接收, \\n\n\ 段落缓冲后 mdprint 彩色渲染 - 日志系统: charmbracelet/log v2 双写(stderr + log.yml), yunshu log 命令 - 会议室架构: dialog(main) + weather/profile/note(sub) 多 Agent 编排 - 泛型工具注册: NewTool[T] 反射推导 JSON Schema, 类型安全 - 安全加固: safeMemoryPath 三段校验(EvalSymlinks+Rel), maxToolCalls=2 - 性能优化: sync.Once 延迟加载, note 一步完成, obs/summary 合并 - Prompt 适配: 流式输出原则(先调工具不说话), 单 Agent 查询跳过 obs+summary - 文档: AGENTS.md + architecture.md + changelog.md 全部同步至 v2.3.0
This commit is contained in:
133
toolschema.go
Normal file
133
toolschema.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func structToSchema(t reflect.Type) Schema {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return typeToSchema(t)
|
||||
}
|
||||
|
||||
schema := Schema{
|
||||
"type": "object",
|
||||
"properties": map[string]any{},
|
||||
}
|
||||
|
||||
properties := schema["properties"].(map[string]any)
|
||||
var required []any
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
f := t.Field(i)
|
||||
|
||||
if !f.IsExported() {
|
||||
continue
|
||||
}
|
||||
|
||||
jsonTag := f.Tag.Get("json")
|
||||
if jsonTag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.Split(jsonTag, ",")[0]
|
||||
if name == "" {
|
||||
name = strings.ToLower(f.Name[:1]) + f.Name[1:]
|
||||
}
|
||||
|
||||
if !strings.Contains(jsonTag, "omitempty") {
|
||||
required = append(required, name)
|
||||
}
|
||||
|
||||
fieldSchema := typeToSchema(f.Type)
|
||||
|
||||
if desc := f.Tag.Get("description"); desc != "" {
|
||||
fieldSchema["description"] = desc
|
||||
}
|
||||
|
||||
if enum := f.Tag.Get("enum"); enum != "" {
|
||||
vals := strings.Split(enum, ",")
|
||||
enumVals := make([]any, len(vals))
|
||||
for i, v := range vals {
|
||||
enumVals[i] = strings.TrimSpace(v)
|
||||
}
|
||||
fieldSchema["enum"] = enumVals
|
||||
}
|
||||
|
||||
properties[name] = fieldSchema
|
||||
}
|
||||
|
||||
if len(required) > 0 {
|
||||
schema["required"] = required
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
func typeToSchema(t reflect.Type) Schema {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.String:
|
||||
return Schema{"type": "string"}
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return Schema{"type": "integer"}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return Schema{"type": "number"}
|
||||
case reflect.Bool:
|
||||
return Schema{"type": "boolean"}
|
||||
case reflect.Slice, reflect.Array:
|
||||
items := typeToSchema(t.Elem())
|
||||
return Schema{"type": "array", "items": items}
|
||||
case reflect.Interface:
|
||||
return Schema{}
|
||||
case reflect.Map:
|
||||
m := Schema{"type": "object"}
|
||||
if t.Elem().Kind() != reflect.Interface {
|
||||
m["additionalProperties"] = typeToSchema(t.Elem())
|
||||
}
|
||||
return m
|
||||
case reflect.Struct:
|
||||
return structToSchema(t)
|
||||
default:
|
||||
return Schema{"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
func NewTool[T any](name, description string, fn func(T) (string, error)) *ToolDef {
|
||||
var zero T
|
||||
t := reflect.TypeOf(zero)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
panic(fmt.Sprintf("NewTool: %T 不是结构体类型", zero))
|
||||
}
|
||||
|
||||
schema := structToSchema(t)
|
||||
|
||||
return &ToolDef{
|
||||
Name: name,
|
||||
Description: description,
|
||||
Parameters: schema,
|
||||
Execute: func(args map[string]any) (string, error) {
|
||||
data, err := json.Marshal(args)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("序列化参数失败: %w", err)
|
||||
}
|
||||
var typed T
|
||||
if err := json.Unmarshal(data, &typed); err != nil {
|
||||
return "", fmt.Errorf("参数解析失败: %w", err)
|
||||
}
|
||||
return fn(typed)
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user