summaryrefslogtreecommitdiffhomepage
path: root/.rules/plan/15-30-retarget-chat-and-counttokens-listmodels-specs.md
diff options
context:
space:
mode:
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.md190
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.