diff options
| author | Adam Malczewski <[email protected]> | 2026-04-30 20:24:33 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-04-30 20:24:33 +0900 |
| commit | 262aa7395c50b449ce0a897f28b1e33c319f5dc7 (patch) | |
| tree | 2ccc7c7f6402e76aea6b8788046215e82650fdfc /.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md | |
| parent | 1e7a273bda744f93f230d21df895b54d2a81ce15 (diff) | |
| download | dispatch-adapter-minimax-main.tar.gz dispatch-adapter-minimax-main.zip | |
Diffstat (limited to '.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md')
| -rw-r--r-- | .rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md b/.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md new file mode 100644 index 0000000..ab62f56 --- /dev/null +++ b/.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md @@ -0,0 +1,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. |
