| name | go-coding-standards |
| description | Use when writing or reviewing Go code — explains harness9 project coding conventions and patterns |
| trigger | write, review, refactor, add, implement |
harness9 Go 编码规范
命名规范
| 类别 | 规范 | 示例 |
|---|
| 包名 | 小写、单单词、无下划线 | engine、provider、schema |
| 导出类型/函数 | PascalCase | AgentEngine、NewRegistry |
| 未导出类型/函数 | camelCase | mainLoop、runLoop |
| 接口名 | 以 -er 后缀为惯例 | Provider、Registry、BaseTool |
| 常量 | PascalCase(导出)或 camelCase(未导出),不使用全大写 | RoleSystem、maxLogOutputLen |
| 配置选项函数 | With 前缀 | WithMaxTurns、WithToolTimeout |
错误处理
- 显式检查所有
error 返回值,禁止 _ 忽略
- 错误消息不以大写字母开头、不以句号结尾
- 使用
fmt.Errorf("context: %w", err) 包装错误,保留错误链
result, err := doSomething()
if err != nil {
return fmt.Errorf("do something: %w", err)
}
result, _ := doSomething()
构造函数
命名规范:New + 类型名
func NewReadFileTool(workDir string) *ReadFileTool {
return &ReadFileTool{workDir: filepath.Clean(workDir)}
}
接口定义原则
接口定义在使用者侧,而非实现者侧。
type Registry interface {
Register(tool BaseTool) error
GetAvailableTools() []schema.ToolDefinition
Execute(ctx context.Context, call schema.ToolCall) schema.ToolResult
}
并发模式
并发工具执行使用预分配切片 + 索引写入,确保结果顺序:
results := make([]schema.ToolResult, len(toolCalls))
var wg sync.WaitGroup
for i, tc := range toolCalls {
wg.Add(1)
go func() {
defer wg.Done()
toolCtx, cancel := context.WithTimeout(ctx, e.toolTimeout)
defer cancel()
results[i] = e.registry.Execute(toolCtx, tc)
}()
}
wg.Wait()
添加新工具的步骤
- 在
internal/tools/ 下创建 xxx.go,实现 BaseTool 接口
- 使用
safePath() 校验所有文件路径参数
- 在
internal/tools/xxx_test.go 中添加表驱动测试
- 在
cmd/harness9/main.go 中注册工具
type MyTool struct {
workDir string
}
func (t *MyTool) Name() string { return "my_tool" }
func (t *MyTool) Definition() schema.ToolDefinition { }
func (t *MyTool) Execute(ctx context.Context, args json.RawMessage) (string, error) { }
测试规范
- 使用标准库
testing 包,不引入第三方断言库
- 表驱动测试优先
- 运行:
go test ./...
func TestXxx(t *testing.T) {
cases := []struct {
name string
input string
want string
}{
{"normal", "foo", "bar"},
{"empty", "", ""},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := Xxx(tc.input)
if got != tc.want {
t.Errorf("got %q, want %q", got, tc.want)
}
})
}
}
代码检查
提交前必须通过:
gofmt -l .
go vet ./...
go test ./...