1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# Phase 11 — Errors module rename and retarget
**Estimated time:** ~15 minutes
**Touches:** `lib/dispatch/adapter/minimax/errors.rb` and every file
that references `ClaudeErrors` or `OverloadedError`.
## Goal
The errors module is currently `Dispatch::Adapter::ClaudeErrors`.
Rename it to `Dispatch::Adapter::MiniMaxErrors`. The mapping logic
(401/403 → AuthenticationError, 429 → RateLimitError, 529 →
OverloadedError, 400/422 → RequestError, 5xx → ServerError) stays the
same. Update the `PROVIDER` constant.
The class `OverloadedError < RateLimitError` stays — Anthropic uses 529
to signal overload and MiniMax MAY too; even if MiniMax never sends
529, the class is harmless dead branch coverage.
## Steps
### 1. Rewrite `lib/dispatch/adapter/minimax/errors.rb`
```ruby
# frozen_string_literal: true
module Dispatch
module Adapter
class OverloadedError < RateLimitError; end
module MiniMaxErrors
module_function
PROVIDER = "MiniMax"
def handle_response!(response)
return if response.is_a?(Net::HTTPSuccess)
code = response.code.to_i
msg = parse_message(response.body)
retry_after = response["Retry-After"]&.to_i
case code
when 401, 403 then raise AuthenticationError.new(msg, status_code: code, provider: PROVIDER)
when 429 then raise RateLimitError.new(msg, status_code: code, provider: PROVIDER, retry_after:)
when 529 then raise OverloadedError.new(msg, status_code: code, provider: PROVIDER, retry_after:)
when 400, 422 then raise RequestError.new(msg, status_code: code, provider: PROVIDER)
when 500..599 then raise ServerError.new(msg, status_code: code, provider: PROVIDER)
else raise Error.new(msg, status_code: code, provider: PROVIDER)
end
end
def parse_message(body)
parsed = JSON.parse(body.to_s)
# Anthropic shape: {"error":{"message":"..."}}
# MiniMax may also use the same shape; keep the dig.
return parsed.dig("error", "message").to_s unless parsed.dig("error", "message").nil?
# Fallback: top-level "message" key (some MiniMax surfaces use this).
return parsed["message"].to_s if parsed["message"]
body.to_s
rescue JSON::ParserError
body.to_s
end
end
end
end
```
Notes on `parse_message`:
- Adds a fallback for a top-level `"message"` key. We don't yet know
MiniMax's exact error JSON shape, but supporting both `{error:{message}}`
and `{message}` is cheap and forwards-compatible.
- If neither matches, falls back to the raw body.
### 2. Find every reference to `ClaudeErrors` and update
```bash
grep -rn 'ClaudeErrors\|ClaudeErrors::PROVIDER' lib/ spec/ sig/
```
Replace each occurrence with `MiniMaxErrors`. Common locations:
- `lib/dispatch/adapter/minimax/sse_parser.rb`
(`raise RequestError.new(..., provider: ClaudeErrors::PROVIDER)`)
- `lib/dispatch/adapter/minimax/http_client.rb`
- `lib/dispatch/adapter/minimax/stream_collector.rb`
- `lib/dispatch/adapter/minimax/usage_client.rb` — DELETED in phase 02,
shouldn't appear, but double-check.
- `lib/dispatch/adapter/minimax.rb` (top-level adapter)
Also confirm the rbs sig file mirrors the rename:
```bash
grep -n 'ClaudeErrors' sig/dispatch/adapter/minimax.rbs
```
If there's a sig declaration for `ClaudeErrors`, rename to
`MiniMaxErrors`.
### 3. Confirm `errors.rb` is required
`lib/dispatch/adapter/minimax.rb` should have
`require_relative "minimax/errors"` near the top of its requires list.
If phase 01 left it as `require_relative "minimax/errors"` already, no
change needed. The new module name `MiniMaxErrors` is autoloaded via
that file.
## Acceptance criteria
- `grep -rn 'ClaudeErrors' lib/ spec/ sig/` returns ZERO matches.
- `Dispatch::Adapter::MiniMaxErrors::PROVIDER == "MiniMax"`.
- `Dispatch::Adapter::MiniMaxErrors.handle_response!(...)` raises the
correct mapped error class for each status code as documented above.
- `parse_message('{"error":{"message":"oops"}}') == "oops"`.
- `parse_message('{"message":"oops"}') == "oops"`.
- `parse_message("not json") == "not json"`.
- `bundle exec rubocop --autocorrect-all` exits 0.
## Verification
Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop must be clean. `errors_spec.rb` failures referencing
`ClaudeErrors` are addressed in phase 16. Failures NOT explainable by
that rename must be fixed before calling `ask_for_next_plan`.
|