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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# Phase 06 — Pricing zero
**Estimated time:** ~15 minutes
**Touches:** `lib/dispatch/adapter/minimax/pricing_table.rb`,
`lib/dispatch/adapter/minimax/data/claude_pricing.json` (or whatever the
JSON data file is named after phase 01),
`lib/dispatch/adapter/minimax/response_builder.rb` (cost calculation).
## Goal
Token Plan is request-quota, not per-token. Setting per-token rates would
mislead callers. Instead, keep the `Usage#cost` field for API stability
but always populate it as `0.0`.
`PricingTable` becomes a stub: it answers `context_window` /
`max_output_tokens` / `lookup` correctly for known MiniMax models, but
`lookup` returns a `ModelPricing` whose four `*_per_mtok` fields are all
zero.
## Steps
### 1. Replace the pricing JSON data file
The current data file (likely
`lib/dispatch/adapter/minimax/data/claude_pricing.json`) contains
Anthropic per-MTok rates. Replace it with a MiniMax catalog containing
zeros for every cost field. RENAME the file to
`lib/dispatch/adapter/minimax/data/minimax_pricing.json`.
```json
{
"MiniMax-M2.7": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2.7-highspeed": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2.5": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2.5-highspeed": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2.1": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2.1-highspeed": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
},
"MiniMax-M2": {
"context_window": 204800,
"max_output_tokens": 16384,
"input_per_mtok": 0.0,
"output_per_mtok": 0.0,
"cache_read_per_mtok": 0.0,
"cache_write_per_mtok": 0.0
}
}
```
`max_output_tokens` is set to 16,384 because MiniMax's documented
`max_tokens` field caps generation; the figure is a conservative default
(the Anthropic SDK request shape uses `max_tokens` and MiniMax accepts up
to whatever the model supports; we'll let MiniMax bound it server-side
for anything larger).
### 2. Update `lib/dispatch/adapter/minimax/pricing_table.rb`
- Change `DATA_PATH` to point at the new filename:
`File.expand_path("data/minimax_pricing.json", __dir__)`.
- Leave the four module-level helper methods (`lookup`, `context_window`,
`max_output_tokens`, `known_ids`) UNCHANGED. They will return correct
values from the new zeroed JSON.
### 3. Confirm `Usage#cost` plumbing
In `lib/dispatch/adapter/minimax/response_builder.rb`, find the
`build_usage` method (and / or `build_usage_cost` if separate). The
existing logic computes cost as `(input_tokens * input_per_mtok / 1M) +
…`. With every `*_per_mtok` field zero, this naturally evaluates to 0.0
— no logic change is needed.
DO NOT short-circuit cost to a hardcoded `0.0`. Let it flow through the
existing arithmetic so that if a future MiniMax pricing model is
populated, the same plumbing will Just Work.
If the existing code calls `pricing.input_per_mtok * input_tokens` and
`pricing` can be `nil` for unknown models, ensure it gracefully returns
`0.0` (not `nil`) when `pricing` is nil. Add a guard if missing:
```ruby
return UsageCost.new(input_cost: 0.0, output_cost: 0.0,
cache_read_cost: 0.0, cache_write_cost: 0.0,
total_cost: 0.0) if pricing.nil?
```
(Field names should match whatever `Dispatch::Adapter::UsageCost`
actually exposes — check the interface gem if uncertain.)
### 4. Delete or update specs that asserted on real prices
If `spec/dispatch/adapter/minimax/pricing_table_spec.rb` has examples
that expect non-zero values for Anthropic models, those examples will
fail after this phase. Update them to reflect MiniMax's zero rates and
the seven new model IDs. The full retarget is in phase 16, but minor
adjustments here to keep the spec passing are fine — DO NOT weaken
or skip examples; either rewrite them correctly now or expect their
failures to be fixed in phase 16.
If you choose to defer to phase 16, ensure the failures are clearly
attributable to "expected Anthropic prices, got zero" (not a load error,
not a syntax error, not a NoMethodError).
## Acceptance criteria
- The JSON data file is named `minimax_pricing.json` and lives under
`lib/dispatch/adapter/minimax/data/`.
- `claude_pricing.json` does NOT exist.
- `PricingTable.known_ids` returns exactly the 7 MiniMax model IDs.
- `PricingTable.context_window("MiniMax-M2.7")` returns `204_800`.
- `PricingTable.lookup("MiniMax-M2.7").input_per_mtok` is `0.0`.
- `PricingTable.lookup("nonexistent-model")` returns `nil`.
- `bundle exec rubocop --autocorrect-all` exits 0.
## Verification
Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop must be clean. The `pricing_table_spec.rb` failures are
acceptable as long as they only stem from old Anthropic price assertions
(retargeted in phase 16). Any failure NOT of that shape must be fixed
before calling `ask_for_next_plan`.
|