summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md
blob: ab62f56a9b1bf081b21d7479610a2aed2e82b28b (plain)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# Phase 15 — Retarget chat, count_tokens, and list_models specs

**Estimated time:** ~30 minutes
**Touches:**
`spec/dispatch/adapter/minimax/chat_spec.rb`,
`spec/dispatch/adapter/minimax/chat_non_streaming_spec.rb`,
`spec/dispatch/adapter/minimax/chat_streaming_spec.rb`,
`spec/dispatch/adapter/minimax/chat_streaming_retry_spec.rb`,
`spec/dispatch/adapter/minimax/count_tokens_spec.rb`,
`spec/dispatch/adapter/minimax/list_models_spec.rb`.

## Goal

Update the integration-style specs that drive the public adapter API
through HTTP stubs. The major changes:

- `stub_request(...).to_return(...)` URLs change from
  `https://api.anthropic.com/v1/messages` to
  `https://api.minimax.io/anthropic/v1/messages` (and likewise for
  `/v1/messages/count_tokens` and `/v1/models`).
- Adapter constructor no longer takes `token_path:`, `is_oauth:`,
  `token_store:`, or `user_agent_override:`. It now takes `api_key:`,
  optionally `key_path:`, and the other surviving kwargs from phase
  04.
- Authentication header check changes from
  `X-Api-Key` / OAuth-bearer logic to a simple
  `Authorization: Bearer <key>`.
- No more `anthropic-version`, `anthropic-beta`, `x-stainless-*`, or
  `User-Agent` header presence assertions — those headers are gone.
- Response and SSE bodies come from the new fixtures.
- Cost assertions expect `0.0`.

## Pre-reading

Read each spec file before editing:

1. `spec/dispatch/adapter/minimax/chat_spec.rb` (top-level adapter
   chat orchestration)
2. `spec/dispatch/adapter/minimax/chat_non_streaming_spec.rb`
3. `spec/dispatch/adapter/minimax/chat_streaming_spec.rb`
4. `spec/dispatch/adapter/minimax/chat_streaming_retry_spec.rb`
5. `spec/dispatch/adapter/minimax/count_tokens_spec.rb`
6. `spec/dispatch/adapter/minimax/list_models_spec.rb`

Also re-skim:

- `lib/dispatch/adapter/minimax.rb` (the public class — what kwargs
  does the constructor take post-phase-04?)
- `spec/fixtures/sse/*.sse` and `spec/fixtures/responses/*.json`
  (post-phase-12 content)

## Common changes across all six specs

### 1. Adapter construction

OLD (typical):

```ruby
adapter = described_class.new(
  api_key: "test-key",
  token_path: tmp_path,
  is_oauth: false,
  base_url: "https://api.anthropic.com"
)
```

NEW:

```ruby
adapter = described_class.new(
  api_key: "test-key",
  key_path: tmp_path,            # only if the test exercises file-loading
  base_url: "https://api.minimax.io/anthropic"
)
```

Drop `is_oauth:`, `token_path:`, `token_store:`, `user_agent_override:`,
`extra_betas:`, `interleaved_thinking:` from every call.

### 2. URL stubs

```ruby
stub_request(:post, "https://api.minimax.io/anthropic/v1/messages")
stub_request(:post, "https://api.minimax.io/anthropic/v1/messages/count_tokens")
stub_request(:get,  "https://api.minimax.io/anthropic/v1/models")
```

### 3. Header-presence assertions

Remove every `with(headers: ...)` assertion that mentioned
`anthropic-version`, `anthropic-beta`, `x-stainless-*`, `User-Agent`
(claude-cli), or `X-Api-Key`.

Keep the assertion that the request includes:

```ruby
"Authorization" => "Bearer test-key",
"Content-Type"  => "application/json"
```

For streaming requests:

```ruby
"Accept" => "text/event-stream"
```

For non-streaming:

```ruby
"Accept" => "application/json"
```

### 4. Response model id assertions

Replace any `expect(response.model).to eq("claude-sonnet-...")` with
`expect(response.model).to eq("MiniMax-M2.7")`.

### 5. Token / cost assertions

Token counts now match the new fixtures (15/8 for text, 50/18 for
tool-use, 42/24 for thinking). Cost assertions: any
`expect(usage.cost.total_cost).to be > 0` becomes
`expect(usage.cost.total_cost).to eq(0.0)`.

### 6. Drop cloaking / OAuth / billing-payload examples

DELETE any example that asserted on:

- The synthetic billing-payload system block.
- Auto-generated `metadata.user_id`.
- `proxy_<toolname>` request shape on the wire.
- Bearer-vs-X-Api-Key branching from the `sk-ant-oat` prefix.
- The `claude-3-5-haiku` skip-billing-block special case.
- `usage_report` (separate spec was already deleted in phase 02; if
  any reference survived, delete it).

### 7. Strict-fallback retry examples (chat_streaming_retry_spec)

Update the 400-error fixture used to trigger the fallback to use one
of MiniMax's plausible error shapes. The spec should still verify:

- On a 400 with grammar/schema-too-large/complex error, the request is
  retried once with `disable_strict_tools: true` forwarded to the
  request builder.
- `@strict_disabled = true` latch is set after the first fallback.
- Subsequent calls automatically pass `disable_strict_tools: true`
  without re-incurring the fallback round-trip.

### 8. count_tokens spec

If MiniMax's `/v1/messages/count_tokens` endpoint returns an HTTP 404
(unknown — we are guessing), the existing graceful degradation
(`rescue StandardError; -1`) should kick in. Add a test case for that:

```ruby
it "returns -1 when count_tokens endpoint is unavailable" do
  stub_request(:post, "https://api.minimax.io/anthropic/v1/messages/count_tokens")
    .to_return(status: 404, body: '{"error":{"message":"not found"}}')

  expect(adapter.count_tokens(messages: [...], system: nil, tools: [])).to eq(-1)
end
```

But also keep a successful-path test that stubs a 200 with
`{"input_tokens": 15}` so the happy path is exercised.

### 9. list_models spec

Same pattern: add tests for both the happy path (stubbed `/v1/models`
returning a `data: [...]` array) and the fallback (404 → returns the
hardcoded 7-model catalog from `PricingTable.known_ids`).

The spec should verify that when both runtime and bundled lists are
available, the result is deduplicated by id (no model appears twice).

## Acceptance criteria

- All six retargeted specs pass cleanly.
- No `.skip` or `pending` examples remain in any.
- `grep -n 'api.anthropic.com\|claude-sonnet\|claude-3\|sk-ant-oat\|is_oauth\|proxy_\|claude-cli\|x-stainless\|anthropic-beta\|anthropic-version\|X-Api-Key' spec/dispatch/adapter/minimax/chat*.rb spec/dispatch/adapter/minimax/{count_tokens,list_models}_spec.rb`
  returns ZERO matches.
- `bundle exec rubocop --autocorrect-all` exits 0.

## Verification

Run `run_tests` with `project_path=reference/dispatch-adapter-minimax`.
Rubocop must be clean. The six retargeted specs must pass. Failures in
the smaller specs (model_catalog, pricing, errors, strict_fallback,
http_client, rate_limiter, main `minimax_spec.rb`) are acceptable here
and addressed in phase 16.