fere-sdk 0.1.0.dev8__tar.gz → 0.1.0.dev11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fere-sdk
3
- Version: 0.1.0.dev8
3
+ Version: 0.1.0.dev11
4
4
  Summary: Python SDK for the FereAI Gateway API
5
5
  Author-email: Fere AI <info@fere.ai>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fere-sdk"
3
- version = "0.1.0.dev8"
3
+ version = "0.1.0.dev11"
4
4
  description = "Python SDK for the FereAI Gateway API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -98,7 +98,9 @@ class FereClient:
98
98
  elif event.event == "done":
99
99
  result["done"] = event.data
100
100
  elif event.event == "error":
101
- raise RuntimeError(event.data.get("message", str(event.data)))
101
+ raise RuntimeError(
102
+ event.data.get("message", str(event.data))
103
+ )
102
104
 
103
105
  if tool_responses:
104
106
  result["tool_responses"] = tool_responses
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import logging
6
7
  from collections.abc import AsyncIterator
7
8
  from typing import Any
8
9
 
@@ -22,6 +23,8 @@ from .models import (
22
23
  WithdrawRequest,
23
24
  )
24
25
 
26
+ logger = logging.getLogger(__name__)
27
+
25
28
  DEFAULT_BASE_URL = "https://api.fereai.xyz"
26
29
 
27
30
 
@@ -81,7 +84,6 @@ class FereAPI:
81
84
  params=params,
82
85
  )
83
86
  if resp.status_code == 401:
84
- # Token expired — refresh and retry
85
87
  self._auth.clear_token()
86
88
  headers = await self._headers()
87
89
  resp = await self._client.get(
@@ -141,9 +143,14 @@ class FereAPI:
141
143
  thread_id: str | None = None,
142
144
  agent: str = "ProAgent",
143
145
  ) -> AsyncIterator[ChatEvent]:
144
- """POST /v1/chat — returns an async iterator of SSE events."""
146
+ """POST /v1/chat — returns an async iterator of SSE events.
147
+
148
+ Uses a 1200s read timeout because research queries (especially
149
+ ProDeepResearchAgent) can take up to 20 minutes with long gaps
150
+ between SSE events while the server plans and researches.
151
+ """
145
152
  headers = await self._headers()
146
- body = {
153
+ body: dict[str, Any] = {
147
154
  "query": query,
148
155
  "stream": True,
149
156
  "agent": agent,
@@ -151,11 +158,15 @@ class FereAPI:
151
158
  if thread_id:
152
159
  body["thread_id"] = thread_id
153
160
 
161
+ chat_timeout = httpx.Timeout(
162
+ connect=30.0, read=1200.0, write=30.0, pool=30.0
163
+ )
154
164
  async with self._client.stream(
155
165
  "POST",
156
166
  f"{self.base_url}/v1/chat",
157
167
  json=body,
158
168
  headers=headers,
169
+ timeout=chat_timeout,
159
170
  ) as resp:
160
171
  resp.raise_for_status()
161
172
  event_type = ""
@@ -169,8 +180,13 @@ class FereAPI:
169
180
  try:
170
181
  data = json.loads(raw)
171
182
  except (json.JSONDecodeError, ValueError):
172
- data = {"raw": raw}
173
- yield ChatEvent(event=event_type, data=data)
183
+ logger.debug(
184
+ "Unparseable SSE data: %r", raw
185
+ )
186
+ continue
187
+ yield ChatEvent(
188
+ event=event_type, data=data
189
+ )
174
190
 
175
191
  async def get_threads(self, skip: int = 0, limit: int = 10) -> list[dict]:
176
192
  """GET /v1/chat/threads"""
@@ -371,7 +387,8 @@ class FereAPI:
371
387
  try:
372
388
  data = json.loads(raw)
373
389
  except (json.JSONDecodeError, ValueError):
374
- data = {"raw": raw}
390
+ logger.debug("Unparseable SSE data: %r", raw)
391
+ continue
375
392
  yield ChatEvent(event=event_type, data=data)
376
393
 
377
394
  # ----------------------------------------------------------
File without changes
File without changes