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 14 — Retarget response-builder and streaming-internals specs
**Estimated time:** ~25 minutes
**Touches:**
`spec/dispatch/adapter/minimax/response_builder_spec.rb`,
`spec/dispatch/adapter/minimax/sse_parser_spec.rb`,
`spec/dispatch/adapter/minimax/stream_collector_spec.rb`.
## Goal
Update the three specs that consume the new fixtures created in phase
12. The structural change is small: with `is_oauth` and cloaking gone
(phase 02), there is no `proxy_` prefix to strip, and the response /
stream pipelines are pure Anthropic-compatible parsers fed by MiniMax-
shaped data.
## Pre-reading
1. `spec/fixtures/sse/*.sse` (already updated in phase 12)
2. `spec/fixtures/responses/*.json` (already updated in phase 12)
3. `lib/dispatch/adapter/minimax/response_builder.rb`
4. `lib/dispatch/adapter/minimax/sse_parser.rb`
5. `lib/dispatch/adapter/minimax/stream_collector.rb`
## Steps for response_builder_spec.rb
### 1. Drop the `is_oauth` parameter from every call
`ResponseBuilder.build(json, model_info: ..., is_oauth: ...)` becomes
`ResponseBuilder.build(json, model_info: ...)`. Phase 02 removed the
keyword from the lib code; remove it from all spec calls here.
### 2. Update fixture references and assertions
The fixtures are now MiniMax-flavoured:
- `model: "MiniMax-M2.7"` instead of a Claude id.
- Token counts changed (input 15/50/42, output 8/18/24).
- `id` strings begin with `msg_minimax_*` and `toolu_minimax_*`.
- Tool name in tool-use fixtures is `"get_weather"` with input
`{"city":"Boston"}`.
Update every assertion that compared against old values.
### 3. Drop the cloaking strip-prefix examples
Any example asserting that `proxy_get_weather` arrives in the response
and is stripped to `get_weather` before being returned should be
DELETED. There is no proxy prefix to strip anymore — MiniMax sends
plain tool names.
### 4. Cost assertions
Examples that asserted `usage.cost.total_cost > 0.0` (or any non-zero
sub-cost) must be updated to expect `0.0` because phase 06 zeroed the
pricing table. Token counts are still meaningful — only the
*per-token rate* is zero.
### 5. Remove cache_creation/cache_read examples that depended on
non-zero pricing if any.
If the old `messages-text.json` exposed cache token counts, the
fixture in phase 12 may not include them. Add them back ONLY IF the
spec needs to exercise that code path (i.e. a `usage_hash` with
`cache_creation_input_tokens` / `cache_read_input_tokens`). If you do,
edit `spec/fixtures/responses/messages-text.json` to add those keys to
`usage` — phase 12's fixture omits them but adding them is fine.
## Steps for sse_parser_spec.rb
### 1. Update model id references
Replace `"claude-sonnet-4-5-20250929"` (or whatever Claude model id was
used) with `"MiniMax-M2.7"` in any in-spec hand-built event payloads.
### 2. Re-load fixtures
Specs that read SSE fixtures by path (`File.read("spec/fixtures/sse/text-only.sse")`)
will pick up the new content automatically. Update the assertions to
match the new event count and content:
- `text-only.sse` → 8 frames (text-only fixture: message_start,
content_block_start, ping, content_block_delta×2, content_block_stop,
message_delta, message_stop). Verify by reading the fixture.
- `tool-use.sse` → 7 frames.
- `thinking-then-text.sse` → 11 frames.
Update text/tool/thinking string assertions to match the new fixture
content (`"Hello, world!"` → `"Hello, "` + `"world!"`,
`"get_weather"` with city=Boston, etc.).
### 3. Truncated fixtures
`truncated-mid-text.sse` ends mid-frame after emitting some text
deltas. The parser is content-agnostic at chunk boundary; the higher-
level `StreamCollector` decides whether to retry. The parser-level
spec should assert that `flush` raises `RequestError` (because there
is dangling non-empty data when the stream ends).
`truncated-before-message-start.sse` is just a `ping` event followed
by EOF — the parser yields the ping (or silently drops it depending on
implementation) and `flush` is a no-op since there is no dangling data.
## Steps for stream_collector_spec.rb
### 1. Drop `is_oauth:` from `StreamCollector.new` calls
Phase 02 removed the keyword. Remove from spec setup.
### 2. Update fixture-driven assertions
For the `text-only.sse` fixture, the collector should now assemble:
- One `TextBlock` with text `"Hello, world!"`
- `stop_reason: :end_turn`
- `usage.input_tokens: 15`
- `usage.output_tokens: 8`
- `model: "MiniMax-M2.7"`
For `tool-use.sse`:
- Zero text blocks.
- One `ToolUseBlock` with id `toolu_minimax01`, name `get_weather`,
arguments `{"city" => "Boston"}`.
- `stop_reason: :tool_use`.
- `usage.input_tokens: 50`, `usage.output_tokens: 18`.
For `thinking-then-text.sse`:
- One `ThinkingBlock` with thinking
`"Considering the question... the answer is two."` and signature `""`
(or `nil`, depending on how the existing builder handles empty
signatures — match the actual lib behavior).
- One `TextBlock` with text `"The answer is 2."`
- `stop_reason: :end_turn`.
### 3. Drop cloaking assertions
Any assertion that the collector strips a `proxy_` prefix from tool
names should be DELETED — there is no prefix to strip.
### 4. Cost assertions
Same as response builder spec: update any cost assertions to expect
`0.0` since pricing is zeroed.
## Acceptance criteria
- `response_builder_spec.rb`, `sse_parser_spec.rb`, and
`stream_collector_spec.rb` all pass cleanly.
- No `.skip` or `pending` examples remain in any of the three.
- `grep -n 'is_oauth\|proxy_\|claude-sonnet\|claude-3' spec/dispatch/adapter/minimax/{response_builder_spec,sse_parser_spec,stream_collector_spec}.rb`
returns ZERO matches.
- `bundle exec rubocop --autocorrect-all` exits 0.
## Verification
Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop and these three retargeted specs must pass. Other spec
failures (chat_*, list_models, etc.) are acceptable and fixed in
phases 15–16.
|