agenthub-python 0.4.2__tar.gz → 0.4.3__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.
Files changed (37) hide show
  1. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/PKG-INFO +2 -1
  2. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/ant_messages/client.py +3 -1
  3. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/auto_client.py +4 -4
  4. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/claude5/client.py +3 -1
  5. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/deepseek_v4/client.py +3 -1
  6. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/gemini3_7/client.py +8 -0
  7. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/glm5_3/client.py +3 -1
  8. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/gpt5_6/client.py +1 -0
  9. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/kimi_k3/client.py +3 -1
  10. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/minimax_m3/client.py +1 -0
  11. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_chat/client.py +3 -1
  12. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_responses/client.py +1 -0
  13. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/pyproject.toml +2 -1
  14. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/pyproject.toml.orig +2 -2
  15. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/README.md +0 -0
  16. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/__init__.py +0 -0
  17. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/abort_signal.py +0 -0
  18. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/ant_messages/__init__.py +0 -0
  19. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/base_client.py +0 -0
  20. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/claude5/__init__.py +0 -0
  21. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/deepseek_v4/__init__.py +0 -0
  22. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/errors.py +0 -0
  23. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/gemini3_7/__init__.py +0 -0
  24. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/glm5_3/__init__.py +0 -0
  25. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/gpt5_6/__init__.py +0 -0
  26. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/integration/__init__.py +0 -0
  27. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/integration/playground.py +0 -0
  28. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/integration/tracer.py +0 -0
  29. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/kimi_k3/__init__.py +0 -0
  30. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/minimax_m3/__init__.py +0 -0
  31. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_chat/__init__.py +0 -0
  32. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_embedding/__init__.py +0 -0
  33. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_embedding/client.py +0 -0
  34. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/openai_responses/__init__.py +0 -0
  35. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/registry.py +0 -0
  36. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/types.py +0 -0
  37. {agenthub_python-0.4.2 → agenthub_python-0.4.3}/agenthub/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agenthub-python
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: AgentHub is the LLM API Hub for the Agent era, built for high-precision autonomous agents.
5
5
  Keywords: agent,llm,gemini,claude,gpt
6
6
  Author: PrismShadow
@@ -13,6 +13,7 @@ Requires-Dist: httpx>=0.27.0
13
13
  Requires-Dist: httpx[socks] ; extra == 'dev'
14
14
  Requires-Dist: pytest>=8.4.2 ; extra == 'dev'
15
15
  Requires-Dist: pytest-asyncio>=0.23.0 ; extra == 'dev'
16
+ Requires-Dist: pytest-xdist>=3.6.0 ; extra == 'dev'
16
17
  Requires-Dist: ruff>=0.14.3 ; extra == 'dev'
17
18
  Requires-Dist: pillow>=10.0.0 ; extra == 'dev'
18
19
  Requires-Python: >=3.11
@@ -300,7 +300,9 @@ class AntMessagesClient(LLMClient):
300
300
  elif ant_event_type == "message_stop":
301
301
  event_type = "stop"
302
302
 
303
- elif ant_event_type in ["text", "thinking", "signature", "input_json"]:
303
+ elif ant_event_type in ["text", "thinking", "signature", "input_json", "ping"]:
304
+ # the SDK drops the "ping" heartbeat at the SSE layer; it reaches here only from
305
+ # gateways that relabel it onto another event
304
306
  event_type = "unused"
305
307
 
306
308
  else:
@@ -47,10 +47,6 @@ class AutoLLMClient(LLMClient):
47
47
  ) -> LLMClient:
48
48
  """Create the appropriate client for the given model."""
49
49
  client_type = (client_type or os.getenv("CLIENT_TYPE") or model).lower()
50
- if client_type == "minimax-m3":
51
- from .minimax_m3 import MiniMaxM3Client
52
-
53
- return MiniMaxM3Client(model=model, api_key=api_key, base_url=base_url)
54
50
  # every Gemini generation shares the unified client ("gemini-3" also matches the
55
51
  # gemini-3.7/gemini-3.6/gemini-3.5-flash-lite client types)
56
52
  if any(
@@ -78,6 +74,10 @@ class AutoLLMClient(LLMClient):
78
74
  from .kimi_k3 import KimiK3Client
79
75
 
80
76
  return KimiK3Client(model=model, api_key=api_key, base_url=base_url)
77
+ elif client_type == "minimax-m3":
78
+ from .minimax_m3 import MiniMaxM3Client
79
+
80
+ return MiniMaxM3Client(model=model, api_key=api_key, base_url=base_url)
81
81
  elif "deepseek-v4" in client_type:
82
82
  from .deepseek_v4 import DeepSeekV4Client
83
83
 
@@ -349,7 +349,9 @@ class Claude5Client(LLMClient):
349
349
  elif claude_event_type == "message_stop":
350
350
  event_type = "stop"
351
351
 
352
- elif claude_event_type in ["text", "thinking", "signature", "input_json"]:
352
+ elif claude_event_type in ["text", "thinking", "signature", "input_json", "ping"]:
353
+ # the SDK drops the "ping" heartbeat at the SSE layer; it reaches here only from
354
+ # gateways that relabel it onto another event
353
355
  event_type = "unused"
354
356
 
355
357
  else:
@@ -206,7 +206,9 @@ class DeepSeekV4Client(LLMClient):
206
206
  usage_metadata: UsageMetadata | None = None
207
207
  finish_reason: FinishReason | None = None
208
208
 
209
- if len(model_output.choices) > 0:
209
+ # gateways inject content-free heartbeat chunks on long generations, whose choices
210
+ # the SDK leaves as None rather than an empty list
211
+ if model_output.choices:
210
212
  choice = model_output.choices[0]
211
213
  delta = choice.delta
212
214
 
@@ -376,6 +376,11 @@ class Gemini3_7Client(LLMClient):
376
376
  usage_metadata: UsageMetadata | None = None
377
377
  finish_reason: FinishReason | None = None
378
378
 
379
+ if not model_output.candidates and not model_output.usage_metadata:
380
+ # gateways inject heartbeat chunks on long generations; they map to a chunk with
381
+ # neither candidates nor usage, so there is nothing to emit
382
+ event_type = "unused"
383
+
379
384
  if model_output.candidates:
380
385
  candidate = model_output.candidates[0]
381
386
  content = getattr(candidate, "content", None)
@@ -511,6 +516,9 @@ class Gemini3_7Client(LLMClient):
511
516
  )
512
517
  async for chunk in response_stream:
513
518
  event = self.transform_model_output_to_uni_event(chunk)
519
+ if event["event_type"] == "unused":
520
+ continue
521
+
514
522
  for item in event["content_items"]:
515
523
  if item["type"] == "tool_call":
516
524
  # gemini 3.7 does not support partial tool call, mock a partial tool call event
@@ -239,7 +239,9 @@ class GLM5_3Client(LLMClient):
239
239
  usage_metadata: UsageMetadata | None = None
240
240
  finish_reason: FinishReason | None = None
241
241
 
242
- if len(model_output.choices) > 0:
242
+ # gateways inject content-free heartbeat chunks on long generations, whose choices
243
+ # the SDK leaves as None rather than an empty list
244
+ if model_output.choices:
243
245
  choice = model_output.choices[0]
244
246
  delta = choice.delta
245
247
 
@@ -301,6 +301,7 @@ class GPT5_6Client(LLMClient):
301
301
  "response.reasoning_text.done",
302
302
  "response.content_part.added",
303
303
  "response.content_part.done",
304
+ "keepalive", # gateway heartbeat on long generations; carries no content
304
305
  ]:
305
306
  event_type = "unused"
306
307
 
@@ -267,7 +267,9 @@ class KimiK3Client(LLMClient):
267
267
  usage_metadata: UsageMetadata | None = None
268
268
  finish_reason: FinishReason | None = None
269
269
 
270
- if len(model_output.choices) > 0:
270
+ # gateways inject content-free heartbeat chunks on long generations, whose choices
271
+ # the SDK leaves as None rather than an empty list
272
+ if model_output.choices:
271
273
  choice = model_output.choices[0]
272
274
  delta = choice.delta
273
275
 
@@ -248,6 +248,7 @@ class MiniMaxM3Client(LLMClient):
248
248
  "response.output_item.done",
249
249
  "response.content_part.added",
250
250
  "response.content_part.done",
251
+ "keepalive", # gateway heartbeat on long generations; carries no content
251
252
  ):
252
253
  raise ValueError(f"Unknown output: {model_output}")
253
254
 
@@ -220,7 +220,9 @@ class OpenaiChatClient(LLMClient):
220
220
  usage_metadata: UsageMetadata | None = None
221
221
  finish_reason: FinishReason | None = None
222
222
 
223
- if len(model_output.choices) > 0:
223
+ # gateways inject content-free heartbeat chunks on long generations, whose choices
224
+ # the SDK leaves as None rather than an empty list
225
+ if model_output.choices:
224
226
  choice = model_output.choices[0]
225
227
  delta = choice.delta
226
228
 
@@ -298,6 +298,7 @@ class OpenaiResponsesClient(LLMClient):
298
298
  "response.reasoning_summary_text.done",
299
299
  "response.content_part.added",
300
300
  "response.content_part.done",
301
+ "keepalive", # gateway heartbeat on long generations; carries no content
301
302
  ):
302
303
  event_type = "unused"
303
304
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agenthub-python"
3
- version = "0.4.2"
3
+ version = "0.4.3"
4
4
  description = "AgentHub is the LLM API Hub for the Agent era, built for high-precision autonomous agents."
5
5
  keywords = [
6
6
  "agent",
@@ -33,6 +33,7 @@ dev = [
33
33
  "httpx[socks]",
34
34
  "pytest>=8.4.2",
35
35
  "pytest-asyncio>=0.23.0",
36
+ "pytest-xdist>=3.6.0",
36
37
  "ruff>=0.14.3",
37
38
  "pillow>=10.0.0",
38
39
  ]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agenthub-python"
3
- version = "0.4.2"
3
+ version = "0.4.3"
4
4
  description = "AgentHub is the LLM API Hub for the Agent era, built for high-precision autonomous agents."
5
5
  keywords = ["agent", "llm", "gemini", "claude", "gpt"]
6
6
  readme = "README.md"
@@ -17,7 +17,7 @@ Repository = "https://github.com/Prism-Shadow/agenthub"
17
17
  Issues = "https://github.com/Prism-Shadow/agenthub/issues"
18
18
 
19
19
  [project.optional-dependencies]
20
- dev = ["httpx[socks]", "pytest>=8.4.2", "pytest-asyncio>=0.23.0", "ruff>=0.14.3", "pillow>=10.0.0"]
20
+ dev = ["httpx[socks]", "pytest>=8.4.2", "pytest-asyncio>=0.23.0", "pytest-xdist>=3.6.0", "ruff>=0.14.3", "pillow>=10.0.0"]
21
21
 
22
22
  [build-system]
23
23
  requires = ["uv_build>=0.9.16,<0.10.0"]