# 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 `. - 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_` 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.