classifyOverflow inspects err for overflow signals and returns the matching [OverflowKind], or "" if err is not an overflow error. The classifier runs two tiers, in order: Tier 1 — structured signals (high confidence): * body.error.type == "request_too_large" → OverflowKindWire * body.e
(err error)
| 236 | // ("request too large") textually overlap with token-overflow phrasing in a |
| 237 | // way that benefits from the wire match coming first. |
| 238 | func classifyOverflow(err error) OverflowKind { |
| 239 | if err == nil { |
| 240 | return "" |
| 241 | } |
| 242 | // Already-wrapped errors carry their Kind; respect it. |
| 243 | if coe, ok := errors.AsType[*ContextOverflowError](err); ok && coe.Kind != "" { |
| 244 | return coe.Kind |
| 245 | } |
| 246 | |
| 247 | raw := err.Error() |
| 248 | |
| 249 | // Tier 1: structured body fields. |
| 250 | if body := firstJSONObject(raw); body != nil { |
| 251 | var parsed providerErrorBody |
| 252 | if json.Unmarshal(body, &parsed) == nil && parsed.Error != nil { |
| 253 | if parsed.Error.Type == "request_too_large" { |
| 254 | return OverflowKindWire |
| 255 | } |
| 256 | if code := scalarString(parsed.Error.Code); code == "context_length_exceeded" { |
| 257 | return OverflowKindTokens |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | // Tier 1: HTTP status code (413 → wire). |
| 263 | if se, ok := errors.AsType[*StatusError](err); ok && se.StatusCode == http.StatusRequestEntityTooLarge { |
| 264 | return OverflowKindWire |
| 265 | } |
| 266 | |
| 267 | // Tier 2: substring fallback. Media first (most specific), then wire, |
| 268 | // then tokens. |
| 269 | msg := strings.ToLower(raw) |
| 270 | for _, p := range mediaOverflowPatterns { |
| 271 | if strings.Contains(msg, p) { |
| 272 | return OverflowKindMedia |
| 273 | } |
| 274 | } |
| 275 | for _, p := range wireOverflowPatterns { |
| 276 | if strings.Contains(msg, p) { |
| 277 | return OverflowKindWire |
| 278 | } |
| 279 | } |
| 280 | for _, p := range tokenOverflowPatterns { |
| 281 | if strings.Contains(msg, p) { |
| 282 | return OverflowKindTokens |
| 283 | } |
| 284 | } |
| 285 | return "" |
| 286 | } |
| 287 | |
| 288 | // statusCodeRegex matches HTTP status codes in error messages (e.g., "429", "500", ": 429 ") |
| 289 | var statusCodeRegex = regexp.MustCompile(`\b([45]\d{2})\b`) |