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
|
# Phase 07 — Model catalog
**Estimated time:** ~15 minutes
**Touches:** `lib/dispatch/adapter/minimax/model_catalog.rb`,
`lib/dispatch/adapter/minimax.rb` (only if `list_models` references the
catalog).
## Goal
Update `ModelCatalog.build` and `ModelCatalog.build_from_api` so they
reflect MiniMax's seven supported models and capabilities (per their
docs). The class shape stays the same so callers / specs keep working.
MiniMax compatibility doc capability flags:
- All 7 models support tool calls.
- All 7 models support streaming.
- Vision is NOT supported in any model (image / document content blocks
are explicitly listed as unsupported).
- `premium_request_multiplier` is `nil` (Token Plan is request-quota,
not multiplier-weighted).
## Steps
### 1. Update `lib/dispatch/adapter/minimax/model_catalog.rb`
Two changes:
- Set `supports_vision: false` (MiniMax does not accept image blocks).
- Drop the `"(unrated) #{display_name}"` formatting in
`build_from_api`. With every model in the bundled pricing table, the
`nil` branch is unreachable in practice, but keep the guard:
`display_name` should be returned verbatim. Unknown runtime models
should still produce a usable `ModelInfo`.
Final shape:
```ruby
# frozen_string_literal: true
module Dispatch
module Adapter
class MiniMax < Base
module ModelCatalog
DEFAULT_CONTEXT_WINDOW = 204_800
module_function
# Build a ModelInfo for a known MiniMax model id.
#
# @param id [String]
# @return [Dispatch::Adapter::ModelInfo]
def build(id)
ModelInfo.new(
id: id,
name: id,
max_context_tokens: PricingTable.context_window(id) || DEFAULT_CONTEXT_WINDOW,
supports_vision: false,
supports_tool_use: true,
supports_streaming: true,
premium_request_multiplier: nil,
pricing: PricingTable.lookup(id)
)
end
# Build a ModelInfo from a runtime API entry (from GET /v1/models).
#
# If the model id is in the bundled pricing table, the bundled
# context window is used. Display name from the API entry takes
# precedence over the id.
#
# @param api_entry [Hash]
# @return [Dispatch::Adapter::ModelInfo]
def build_from_api(api_entry)
id = api_entry["id"].to_s
display_name = api_entry["display_name"].to_s
display_name = id if display_name.empty?
pricing = PricingTable.lookup(id)
context_win = PricingTable.context_window(id) || DEFAULT_CONTEXT_WINDOW
ModelInfo.new(
id: id,
name: display_name,
max_context_tokens: context_win,
supports_vision: false,
supports_tool_use: true,
supports_streaming: true,
premium_request_multiplier: nil,
pricing: pricing
)
end
end
end
end
end
```
### 2. Sanity-check `list_models`
Find `def list_models` in `lib/dispatch/adapter/minimax.rb`. It probably
calls `ModelCatalog.build_from_api(entry)` for each runtime entry, then
merges with the hardcoded catalog. Confirm:
- The runtime fetch hits `MODELS_PATH` (`/v1/models`).
- On any error (404, parse failure, network), it falls back to building
`ModelInfo` for each id from `PricingTable.known_ids` via
`ModelCatalog.build`.
- The result is a deduplicated array (by `id`).
- Caching (`@models_cache`, `@models_cache_at`) is intact.
If MiniMax doesn't expose `/v1/models` (we don't know yet), the runtime
branch will return `nil` / `[]` and the hardcoded catalog will be used.
Both outcomes are acceptable.
DO NOT add live network smoke testing here; live testing is post-plan.
## Acceptance criteria
- `ModelCatalog.build("MiniMax-M2.7")` returns a `ModelInfo` with:
- `id: "MiniMax-M2.7"`
- `max_context_tokens: 204_800`
- `supports_vision: false`
- `supports_tool_use: true`
- `supports_streaming: true`
- `pricing` with all four `*_per_mtok` fields zero.
- `ModelCatalog.build("not-a-real-model")` returns a `ModelInfo` with
`pricing: nil` and `max_context_tokens: 204_800` (the default).
- `bundle exec rubocop --autocorrect-all` exits 0.
## Verification
Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop must be clean. `model_catalog_spec.rb` failures are acceptable
(retargeted in phase 16). Any failure outside that file must be fixed
before calling `ask_for_next_plan`.
|