|
6 | 6 | import httpx |
7 | 7 | import pytest |
8 | 8 |
|
9 | | -from zhub.brains.base import ChatChunk |
10 | 9 | from zhub.brains.together import TogetherAdapter |
11 | 10 | from zhub.brains.mistral import MistralAdapter |
12 | 11 | from zhub.brains.cohere import CohereAdapter |
@@ -145,3 +144,48 @@ async def test_cohere_stream_parses_v2_event_shape(): |
145 | 144 | assert body["messages"][-1] == {"role": "user", "content": "x"} |
146 | 145 | headers = fake.last_call["headers"] |
147 | 146 | assert headers["Authorization"] == "Bearer co_test" |
| 147 | + |
| 148 | + |
| 149 | +class _FakeErrorStream: |
| 150 | + def __init__(self, status_code, body): |
| 151 | + self.status_code = status_code |
| 152 | + self._body = body.encode() |
| 153 | + |
| 154 | + async def aiter_lines(self): |
| 155 | + yield self._body.decode() |
| 156 | + |
| 157 | + async def aread(self): |
| 158 | + return self._body |
| 159 | + |
| 160 | + async def __aenter__(self): |
| 161 | + return self |
| 162 | + |
| 163 | + async def __aexit__(self, *exc): |
| 164 | + return None |
| 165 | + |
| 166 | + |
| 167 | +class _FakeErrorClient: |
| 168 | + def __init__(self, status_code, body): |
| 169 | + self._status = status_code |
| 170 | + self._body = body |
| 171 | + |
| 172 | + def stream(self, method, url, **kw): |
| 173 | + return _FakeErrorStream(self._status, self._body) |
| 174 | + |
| 175 | + async def aclose(self): |
| 176 | + pass |
| 177 | + |
| 178 | + |
| 179 | +@pytest.mark.asyncio |
| 180 | +async def test_cohere_stream_raises_on_upstream_error(): |
| 181 | + """A non-2xx body is a JSON error, not Cohere's newline-delimited events — |
| 182 | + the adapter must raise rather than end the stream silently with no content |
| 183 | + (matching the anthropic / openai-compat adapters).""" |
| 184 | + fake = _FakeErrorClient(429, '{"message":"rate limit exceeded"}') |
| 185 | + a = CohereAdapter(api_key="co_test", model="command-r-plus-08-2024", http=fake) |
| 186 | + with pytest.raises(RuntimeError) as ei: |
| 187 | + async for _ in a.stream([{"role": "user", "content": "hi"}]): |
| 188 | + pass |
| 189 | + msg = str(ei.value) |
| 190 | + assert "429" in msg |
| 191 | + assert "rate limit exceeded" in msg |
0 commit comments