"""Smoke tests for POST /v1/messages with stream=true (SSE). Verified live 2026-09-18, < $0.0002 total.""" from __future__ import annotations import json MSG = "/v1/messages" def _events(lines): name = None for line in lines: if line.startswith("event:"): name = line[6:].strip() elif line.startswith("data:"): yield name, json.loads(line[5:].strip()) def test_sse_event_order_and_shapes(anthropic, models): st, gen, hdrs = anthropic("POST", MSG, {"model": models["anthropic"], "max_tokens": 16, "stream": True, "messages": [{"role": "user", "content": "Reply with OK."}]}, stream=True, note="test_streaming basic") assert st == 200 assert "text/event-stream" in {k.lower(): v for k, v in hdrs.items()}["content-type"] evs = list(_events(gen)) names = [n for n, _ in evs] for n, d in evs: assert d["type"] == n # SSE event name == data.type assert names[0] == "message_start" and names[-1] == "message_stop" assert names.count("message_start") == 1 and names.count("message_stop") == 1 assert names.index("content_block_start") < names.index("content_block_delta") < names.index("content_block_stop") < names.index("message_delta") start = evs[0][1]["message"] assert start["content"] == [] and start["stop_reason"] is None and "usage" in start delta = next(d for n, d in evs if n == "message_delta") assert delta["delta"]["stop_reason"] == "end_turn" assert set(delta["usage"]) >= {"input_tokens", "output_tokens", "cache_creation_input_tokens", "cache_read_input_tokens"} text = "".join(d["delta"]["text"] for n, d in evs if n == "content_block_delta" and d["delta"]["type"] == "text_delta") assert "OK" in text assert all(n in {"message_start", "content_block_start", "content_block_delta", "content_block_stop", "message_delta", "message_stop", "ping"} for n in names) def test_sse_tool_use_input_json_delta(anthropic, models): tool = {"name": "get_weather", "description": "Weather for a city", "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}} st, gen, _ = anthropic("POST", MSG, {"model": models["anthropic"], "max_tokens": 48, "stream": True, "tools": [tool], "tool_choice": {"type": "tool", "name": "get_weather"}, "messages": [{"role": "user", "content": "Weather in Paris?"}]}, stream=True, note="test_streaming tool_use") assert st == 200 evs = list(_events(gen)) start = next(d for n, d in evs if n == "content_block_start") assert start["content_block"]["type"] == "tool_use" and start["content_block"]["input"] == {} partial = "".join(d["delta"]["partial_json"] for n, d in evs if n == "content_block_delta" and d["delta"]["type"] == "input_json_delta") assert json.loads(partial).get("city") assert next(d for n, d in evs if n == "message_delta")["delta"]["stop_reason"] == "tool_use"