• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

smallnest / goclaw / 22337106902

24 Feb 2026 04:49AM UTC coverage: 4.317% (-1.5%) from 5.772%
22337106902

push

github

smallnest
refactor agent

411 of 1648 new or added lines in 17 files covered. (24.94%)

2 existing lines in 2 files now uncovered.

1061 of 24577 relevant lines covered (4.32%)

0.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

35.17
/errors/errors.go
1
package errors
2

3
import (
4
        "errors"
5
        "fmt"
6
        "strings"
7
)
8

9
// ErrorCode represents a unique error code
10
type ErrorCode string
11

12
const (
13
        // General errors
14
        ErrCodeUnknown         ErrorCode = "UNKNOWN"
15
        ErrCodeInvalidInput    ErrorCode = "INVALID_INPUT"
16
        ErrCodeInvalidConfig   ErrorCode = "INVALID_CONFIG"
17
        ErrCodeNotFound        ErrorCode = "NOT_FOUND"
18
        ErrCodeAlreadyExists   ErrorCode = "ALREADY_EXISTS"
19
        ErrCodePermission      ErrorCode = "PERMISSION_DENIED"
20
        ErrCodeTimeout         ErrorCode = "TIMEOUT"
21
        ErrCodeRateLimit       ErrorCode = "RATE_LIMIT"
22
        ErrCodeAuth            ErrorCode = "AUTHENTICATION_FAILED"
23
        ErrCodeBilling         ErrorCode = "BILLING_ERROR"
24
        ErrCodeContextOverflow ErrorCode = "CONTEXT_OVERFLOW"
25

26
        // Agent errors
27
        ErrCodeAgentNotRunning  ErrorCode = "AGENT_NOT_RUNNING"
28
        ErrCodeAgentStartFailed ErrorCode = "AGENT_START_FAILED"
29
        ErrCodeAgentStopFailed  ErrorCode = "AGENT_STOP_FAILED"
30
        ErrCodeToolExecution    ErrorCode = "TOOL_EXECUTION_FAILED"
31
        ErrCodeToolNotFound     ErrorCode = "TOOL_NOT_FOUND"
32
        ErrCodeSkillNotFound    ErrorCode = "SKILL_NOT_FOUND"
33
        ErrCodeSkillLoadFailed  ErrorCode = "SKILL_LOAD_FAILED"
34

35
        // Provider errors
36
        ErrCodeProviderUnavailable ErrorCode = "PROVIDER_UNAVAILABLE"
37
        ErrCodeProviderTimeout     ErrorCode = "PROVIDER_TIMEOUT"
38
        ErrCodeProviderError       ErrorCode = "PROVIDER_ERROR"
39
        ErrCodeProviderResponse    ErrorCode = "PROVIDER_RESPONSE_ERROR"
40

41
        // Channel errors
42
        ErrCodeChannelNotConfigured ErrorCode = "CHANNEL_NOT_CONFIGURED"
43
        ErrCodeChannelSendFailed    ErrorCode = "CHANNEL_SEND_FAILED"
44
        ErrCodeChannelReceive       ErrorCode = "CHANNEL_RECEIVE_ERROR"
45

46
        // Memory errors
47
        ErrCodeMemoryNotFound     ErrorCode = "MEMORY_NOT_FOUND"
48
        ErrCodeMemorySaveFailed   ErrorCode = "MEMORY_SAVE_FAILED"
49
        ErrCodeMemoryLoadFailed   ErrorCode = "MEMORY_LOAD_FAILED"
50
        ErrCodeMemorySearchFailed ErrorCode = "MEMORY_SEARCH_FAILED"
51

52
        // Session errors
53
        ErrCodeSessionNotFound  ErrorCode = "SESSION_NOT_FOUND"
54
        ErrCodeSessionCreate    ErrorCode = "SESSION_CREATE_FAILED"
55
        ErrCodeSessionSave      ErrorCode = "SESSION_SAVE_FAILED"
56
        ErrCodeSessionCorrupted ErrorCode = "SESSION_CORRUPTED"
57
)
58

59
// AppError represents a structured application error
60
type AppError struct {
61
        Code       ErrorCode
62
        Message    string
63
        Err        error
64
        StackTrace string
65
        Context    map[string]any
66
}
67

68
// Error implements the error interface
69
func (e *AppError) Error() string {
2✔
70
        if e.Err != nil {
2✔
NEW
71
                return fmt.Sprintf("[%s] %s: %v", e.Code, e.Message, e.Err)
×
NEW
72
        }
×
73
        return fmt.Sprintf("[%s] %s", e.Code, e.Message)
2✔
74
}
75

76
// Unwrap returns the wrapped error
77
func (e *AppError) Unwrap() error {
1✔
78
        return e.Err
1✔
79
}
1✔
80

81
// New creates a new application error
82
func New(code ErrorCode, message string) *AppError {
18✔
83
        return &AppError{
18✔
84
                Code:    code,
18✔
85
                Message: message,
18✔
86
                Context: make(map[string]any),
18✔
87
        }
18✔
88
}
18✔
89

90
// Wrap wraps an existing error with code and message
91
func Wrap(err error, code ErrorCode, message string) *AppError {
1✔
92
        if err == nil {
1✔
NEW
93
                return nil
×
NEW
94
        }
×
95
        return &AppError{
1✔
96
                Code:    code,
1✔
97
                Message: message,
1✔
98
                Err:     err,
1✔
99
                Context: make(map[string]any),
1✔
100
        }
1✔
101
}
102

103
// Wrapf wraps an error with formatted message
NEW
104
func Wrapf(err error, code ErrorCode, format string, args ...any) *AppError {
×
NEW
105
        if err == nil {
×
NEW
106
                return nil
×
NEW
107
        }
×
NEW
108
        return &AppError{
×
NEW
109
                Code:    code,
×
NEW
110
                Message: fmt.Sprintf(format, args...),
×
NEW
111
                Err:     err,
×
NEW
112
                Context: make(map[string]any),
×
NEW
113
        }
×
114
}
115

116
// WithContext adds context to the error
117
func (e *AppError) WithContext(key string, value any) *AppError {
2✔
118
        if e.Context == nil {
2✔
NEW
119
                e.Context = make(map[string]any)
×
NEW
120
        }
×
121
        e.Context[key] = value
2✔
122
        return e
2✔
123
}
124

125
// GetCode returns the error code from an error if it's an AppError
126
func GetCode(err error) ErrorCode {
13✔
127
        var appErr *AppError
13✔
128
        if errors.As(err, &appErr) {
25✔
129
                return appErr.Code
12✔
130
        }
12✔
131
        return ErrCodeUnknown
1✔
132
}
133

134
// GetMessage returns the error message
135
func GetMessage(err error) string {
3✔
136
        if err == nil {
3✔
NEW
137
                return ""
×
NEW
138
        }
×
139
        var appErr *AppError
3✔
140
        if errors.As(err, &appErr) {
6✔
141
                return appErr.Message
3✔
142
        }
3✔
NEW
143
        return err.Error()
×
144
}
145

146
// Is checks if error is of specific type
147
func Is(err error, code ErrorCode) bool {
2✔
148
        var appErr *AppError
2✔
149
        if errors.As(err, &appErr) {
4✔
150
                return appErr.Code == code
2✔
151
        }
2✔
NEW
152
        return false
×
153
}
154

155
// Common error constructors
NEW
156
func InvalidInput(msg string) *AppError {
×
NEW
157
        return New(ErrCodeInvalidInput, msg)
×
NEW
158
}
×
159

NEW
160
func InvalidConfig(msg string) *AppError {
×
NEW
161
        return New(ErrCodeInvalidConfig, msg)
×
NEW
162
}
×
163

164
func NotFound(what string) *AppError {
1✔
165
        return New(ErrCodeNotFound, what+" not found")
1✔
166
}
1✔
167

NEW
168
func AlreadyExists(what string) *AppError {
×
NEW
169
        return New(ErrCodeAlreadyExists, what+" already exists")
×
NEW
170
}
×
171

172
func Timeout(operation string) *AppError {
1✔
173
        return New(ErrCodeTimeout, operation+" timed out")
1✔
174
}
1✔
175

176
func ToolNotFound(name string) *AppError {
1✔
177
        return New(ErrCodeToolNotFound, fmt.Sprintf("tool '%s' not found", name))
1✔
178
}
1✔
179

NEW
180
func ToolExecutionFailed(name string, err error) *AppError {
×
NEW
181
        return Wrap(err, ErrCodeToolExecution, fmt.Sprintf("tool '%s' execution failed", name))
×
NEW
182
}
×
183

NEW
184
func SkillNotFound(name string) *AppError {
×
NEW
185
        return New(ErrCodeSkillNotFound, fmt.Sprintf("skill '%s' not found", name))
×
NEW
186
}
×
187

NEW
188
func ProviderUnavailable(provider string) *AppError {
×
NEW
189
        return New(ErrCodeProviderUnavailable, fmt.Sprintf("provider '%s' is unavailable", provider))
×
NEW
190
}
×
191

NEW
192
func SessionNotFound(id string) *AppError {
×
NEW
193
        return New(ErrCodeSessionNotFound, fmt.Sprintf("session '%s' not found", id))
×
NEW
194
}
×
195

NEW
196
func MemoryOperationFailed(op string, err error) *AppError {
×
NEW
197
        return Wrap(err, ErrCodeMemorySearchFailed, fmt.Sprintf("memory %s operation failed", op))
×
NEW
198
}
×
199

200
// ==============================================================================
201
// Failover Support
202
// ==============================================================================
203

204
// FailoverReason 失败原因类型
205
type FailoverReason string
206

207
const (
208
        // FailoverReasonAuth 认证错误
209
        FailoverReasonAuth FailoverReason = "auth"
210
        // FailoverReasonRateLimit 速率限制
211
        FailoverReasonRateLimit FailoverReason = "rate_limit"
212
        // FailoverReasonTimeout 超时
213
        FailoverReasonTimeout FailoverReason = "timeout"
214
        // FailoverReasonBilling 计费错误
215
        FailoverReasonBilling FailoverReason = "billing"
216
        // FailoverReasonContextOverflow 上下文溢出
217
        FailoverReasonContextOverflow FailoverReason = "context_overflow"
218
        // FailoverReasonUnknown 未知错误
219
        FailoverReasonUnknown FailoverReason = "unknown"
220
)
221

222
// ErrorClassifier 错误分类器接口
223
type ErrorClassifier interface {
224
        ClassifyError(err error) FailoverReason
225
        IsFailoverError(err error) bool
226
}
227

228
// SimpleErrorClassifier 简单的错误分类器实现
229
type SimpleErrorClassifier struct {
230
        authPatterns      []string
231
        rateLimitPatterns []string
232
        timeoutPatterns   []string
233
        billingPatterns   []string
234
}
235

236
// NewSimpleErrorClassifier 创建简单错误分类器
NEW
237
func NewSimpleErrorClassifier() *SimpleErrorClassifier {
×
NEW
238
        return &SimpleErrorClassifier{
×
NEW
239
                authPatterns: []string{
×
NEW
240
                        "invalid api key", "incorrect api key", "invalid token",
×
NEW
241
                        "authentication", "re-authenticate", "unauthorized",
×
NEW
242
                        "forbidden", "access denied", "expired", "401", "403",
×
NEW
243
                },
×
NEW
244
                rateLimitPatterns: []string{
×
NEW
245
                        "rate limit", "too many requests", "429", "quota exceeded",
×
NEW
246
                        "resource_exhausted", "usage limit", "overloaded",
×
NEW
247
                },
×
NEW
248
                timeoutPatterns: []string{
×
NEW
249
                        "timeout", "timed out", "deadline exceeded", "context deadline exceeded",
×
NEW
250
                },
×
NEW
251
                billingPatterns: []string{
×
NEW
252
                        "402", "payment required", "insufficient credits", "billing",
×
NEW
253
                },
×
NEW
254
        }
×
NEW
255
}
×
256

257
// ClassifyError 分类错误
NEW
258
func (c *SimpleErrorClassifier) ClassifyError(err error) FailoverReason {
×
NEW
259
        if err == nil {
×
NEW
260
                return FailoverReasonUnknown
×
NEW
261
        }
×
262

NEW
263
        errMsg := strings.ToLower(err.Error())
×
NEW
264

×
NEW
265
        if c.matchesAny(errMsg, c.authPatterns) {
×
NEW
266
                return FailoverReasonAuth
×
NEW
267
        }
×
NEW
268
        if c.matchesAny(errMsg, c.rateLimitPatterns) {
×
NEW
269
                return FailoverReasonRateLimit
×
NEW
270
        }
×
NEW
271
        if c.matchesAny(errMsg, c.timeoutPatterns) {
×
NEW
272
                return FailoverReasonTimeout
×
NEW
273
        }
×
NEW
274
        if c.matchesAny(errMsg, c.billingPatterns) {
×
NEW
275
                return FailoverReasonBilling
×
NEW
276
        }
×
277

NEW
278
        return FailoverReasonUnknown
×
279
}
280

281
// IsFailoverError 检查是否为可回退的错误
NEW
282
func (c *SimpleErrorClassifier) IsFailoverError(err error) bool {
×
NEW
283
        if err == nil {
×
NEW
284
                return false
×
NEW
285
        }
×
NEW
286
        reason := c.ClassifyError(err)
×
NEW
287
        return reason != FailoverReasonUnknown
×
288
}
289

290
// matchesAny 检查错误消息是否匹配任何模式
NEW
291
func (c *SimpleErrorClassifier) matchesAny(errMsg string, patterns []string) bool {
×
NEW
292
        for _, pattern := range patterns {
×
NEW
293
                if strings.Contains(errMsg, pattern) {
×
NEW
294
                        return true
×
NEW
295
                }
×
296
        }
NEW
297
        return false
×
298
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc