SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
5.7 KB · 94 lines python
Raw Blame History
1"""Smoke tests for xAI Chat Completions (grok-4.3 by default; every call bills ~100-180 reasoning tokens, ~$0.0005).2Uses the `xai` fixture (scripts.live.xai_request) and models["xai"] from tests/conftest.py.3"""4from __future__ import annotations56import json7import time89import pytest1011MSGS = [{"role": "user", "content": "Reply with OK."}]121314def test_minimal_chat_completion_has_reasoning_content(xai, models):15    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32}, est_cost_usd=0.0005, note="test_chat minimal")16    assert st == 200 and body["object"] == "chat.completion"17    msg = body["choices"][0]["message"]18    # Reasoning is always-on and billed inside max_completion_tokens: a long trace can end the turn with19    # finish_reason "length" and an empty content (observed once on 2026-09-19) — tolerate that race.20    fr = body["choices"][0]["finish_reason"]21    assert fr in ("stop", "length")22    if fr == "stop":23        assert "OK" in (msg.get("content") or "")24        assert "reasoning_content" in msg  # reasoning models expose the trace25    u = body["usage"]26    assert u["total_tokens"] == u["prompt_tokens"] + u["completion_tokens"] + u["completion_tokens_details"]["reasoning_tokens"]27    assert "cached_tokens" in u["prompt_tokens_details"] and "cost_in_usd_ticks" in u28    assert body["service_tier"] == "default"293031def test_streaming_chunks_usage_and_done(xai, models):32    st, lines, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32, "stream": True, "stream_options": {"include_usage": True}}, stream=True, est_cost_usd=0.0005, note="test_chat stream")33    assert st == 20034    data = [l[5:].strip() for l in lines if l.startswith("data:")]35    assert data[-1] == "[DONE]"36    chunks = [json.loads(d) for d in data[:-1]]37    assert all(c["object"] == "chat.completion.chunk" for c in chunks)38    assert chunks[-1]["choices"] == [] and chunks[-1]["usage"]["total_tokens"] > 039    assert any(c["choices"] and c["choices"][0].get("finish_reason") == "stop" for c in chunks)40    assert "OK" in "".join(c["choices"][0]["delta"].get("content") or "" for c in chunks if c["choices"])414243def test_json_schema_strict(xai, models):44    schema = {"type": "object", "properties": {"answer": {"type": "string"}, "n": {"type": "integer"}}, "required": ["answer", "n"], "additionalProperties": False}45    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": [{"role": "user", "content": "Reply with answer OK and n 1."}], "max_completion_tokens": 32, "response_format": {"type": "json_schema", "json_schema": {"name": "ok", "strict": True, "schema": schema}}}, est_cost_usd=0.0005, note="test_chat json_schema")46    assert st == 20047    parsed = json.loads(body["choices"][0]["message"]["content"])48    assert set(parsed) == {"answer", "n"} and parsed["n"] == 1495051def test_reasoning_effort_values(xai, models):52    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32, "reasoning_effort": "low"}, est_cost_usd=0.0005, note="test_chat reasoning_effort=low")53    assert st == 200 and body["usage"]["completion_tokens_details"]["reasoning_tokens"] >= 054    st, body, _ = xai("POST", "/v1/chat/completions", {"model": "grok-4.20-0309-non-reasoning", "messages": MSGS, "max_completion_tokens": 32, "reasoning_effort": "low"}, est_cost_usd=0.0002, note="test_chat reasoning_effort on non-reasoning model")55    assert st == 400 and "reasoningEffort" in json.dumps(body)565758def test_unsupported_params_rejected(xai, models):59    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32, "logit_bias": {"1": 1}}, est_cost_usd=0, note="test_chat logit_bias")60    assert st == 400 and "logit_bias" in json.dumps(body)61    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32, "search_parameters": {"mode": "on"}}, est_cost_usd=0, note="test_chat search_parameters retired")62    assert st == 410 and "deprecated" in json.dumps(body).lower()636465def test_deferred_completion_roundtrip(xai, models):66    st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": MSGS, "max_completion_tokens": 32, "deferred": True}, est_cost_usd=0.0005, note="test_chat deferred start")67    assert st == 200 and set(body) == {"request_id"}68    for _ in range(15):69        st, res, _ = xai("GET", f"/v1/chat/deferred-completion/{body['request_id']}", note="test_chat deferred poll")70        if st == 200:71            break72        assert st == 20273        time.sleep(2)74    assert st == 200 and res["object"] == "chat.completion" and "OK" in res["choices"][0]["message"]["content"]757677def test_legacy_completions_retired(xai, models):78    st, body, _ = xai("POST", "/v1/completions", {"model": models["xai"], "prompt": "1, 2, 3,", "max_tokens": 4}, est_cost_usd=0, note="test_chat legacy completions")79    assert st == 400 and "Raw sampling" in json.dumps(body)808182@pytest.mark.run_expensive_tests83def test_prompt_cache_hit_with_prompt_cache_key(xai, models):84    import uuid85    key = str(uuid.uuid4())86    big = "You are a helpful assistant. " * 12087    cached = []88    for i in range(2):89        st, body, _ = xai("POST", "/v1/chat/completions", {"model": models["xai"], "messages": [{"role": "system", "content": big}] + MSGS, "max_completion_tokens": 32, "prompt_cache_key": key}, extra_headers={"x-grok-conv-id": key}, est_cost_usd=0.001, note=f"test_chat cache turn {i+1}")90        assert st == 20091        cached.append(body["usage"]["prompt_tokens_details"]["cached_tokens"])92        time.sleep(1)93    assert cached[1] >= cached[0]94