agenthub-python 0.4.2__tar.gz → 0.4.4__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.
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/PKG-INFO +2 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/ant_messages/client.py +4 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/auto_client.py +4 -4
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/claude5/client.py +5 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/deepseek_v4/client.py +13 -4
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/gemini3_7/client.py +12 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/glm5_3/client.py +5 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/gpt5_6/client.py +2 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/integration/playground.py +2 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/kimi_k3/client.py +5 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/minimax_m3/client.py +3 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_chat/client.py +3 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_responses/client.py +2 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/types.py +1 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/pyproject.toml +2 -1
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/pyproject.toml.orig +2 -2
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/README.md +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/abort_signal.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/ant_messages/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/base_client.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/claude5/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/deepseek_v4/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/errors.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/gemini3_7/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/glm5_3/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/gpt5_6/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/integration/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/integration/tracer.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/kimi_k3/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/minimax_m3/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_chat/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_embedding/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_embedding/client.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/openai_responses/__init__.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/registry.py +0 -0
- {agenthub_python-0.4.2 → agenthub_python-0.4.4}/agenthub/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agenthub-python
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
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
|
|
@@ -75,6 +75,7 @@ class AntMessagesClient(LLMClient):
|
|
|
75
75
|
ThinkingLevel.MEDIUM: {"thinking": {"type": "adaptive"}, "output_config": {"effort": "medium"}},
|
|
76
76
|
ThinkingLevel.HIGH: {"thinking": {"type": "adaptive"}, "output_config": {"effort": "high"}},
|
|
77
77
|
ThinkingLevel.XHIGH: {"thinking": {"type": "adaptive"}, "output_config": {"effort": "xhigh"}},
|
|
78
|
+
ThinkingLevel.MAX: {"thinking": {"type": "adaptive"}, "output_config": {"effort": "max"}},
|
|
78
79
|
}
|
|
79
80
|
return mapping.get(thinking_level)
|
|
80
81
|
|
|
@@ -300,7 +301,9 @@ class AntMessagesClient(LLMClient):
|
|
|
300
301
|
elif ant_event_type == "message_stop":
|
|
301
302
|
event_type = "stop"
|
|
302
303
|
|
|
303
|
-
elif ant_event_type in ["text", "thinking", "signature", "input_json"]:
|
|
304
|
+
elif ant_event_type in ["text", "thinking", "signature", "input_json", "ping"]:
|
|
305
|
+
# the SDK drops the "ping" heartbeat at the SSE layer; it reaches here only from
|
|
306
|
+
# gateways that relabel it onto another event
|
|
304
307
|
event_type = "unused"
|
|
305
308
|
|
|
306
309
|
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
|
|
|
@@ -115,6 +115,8 @@ class Claude5Client(LLMClient):
|
|
|
115
115
|
"thinking": {"type": "adaptive"},
|
|
116
116
|
"output_config": {"effort": "high" if "4-6" in self._model else "xhigh"},
|
|
117
117
|
},
|
|
118
|
+
# every model this client serves is 4.6 or later, and max spans that whole range
|
|
119
|
+
ThinkingLevel.MAX: {"thinking": {"type": "adaptive"}, "output_config": {"effort": "max"}},
|
|
118
120
|
}
|
|
119
121
|
return mapping.get(thinking_level)
|
|
120
122
|
|
|
@@ -349,7 +351,9 @@ class Claude5Client(LLMClient):
|
|
|
349
351
|
elif claude_event_type == "message_stop":
|
|
350
352
|
event_type = "stop"
|
|
351
353
|
|
|
352
|
-
elif claude_event_type in ["text", "thinking", "signature", "input_json"]:
|
|
354
|
+
elif claude_event_type in ["text", "thinking", "signature", "input_json", "ping"]:
|
|
355
|
+
# the SDK drops the "ping" heartbeat at the SSE layer; it reaches here only from
|
|
356
|
+
# gateways that relabel it onto another event
|
|
353
357
|
event_type = "unused"
|
|
354
358
|
|
|
355
359
|
else:
|
|
@@ -54,17 +54,24 @@ class DeepSeekV4Client(LLMClient):
|
|
|
54
54
|
ThinkingLevel.MEDIUM: {"type": "enabled"},
|
|
55
55
|
ThinkingLevel.HIGH: {"type": "enabled"},
|
|
56
56
|
ThinkingLevel.XHIGH: {"type": "enabled"},
|
|
57
|
+
ThinkingLevel.MAX: {"type": "enabled"},
|
|
57
58
|
}
|
|
58
59
|
return mapping[thinking_level]
|
|
59
60
|
|
|
60
61
|
def _convert_reasoning_effort(self, thinking_level: ThinkingLevel) -> str | None:
|
|
61
|
-
"""Convert ThinkingLevel enum to DeepSeek's reasoning_effort.
|
|
62
|
+
"""Convert ThinkingLevel enum to DeepSeek's reasoning_effort.
|
|
63
|
+
|
|
64
|
+
DeepSeek accepts low/high/max and maps medium and xhigh onto high server-side
|
|
65
|
+
(llmsdk_docs/deepseek_v4/docs/thinking-mode.md), so this sends the value the
|
|
66
|
+
server would settle on anyway.
|
|
67
|
+
"""
|
|
62
68
|
mapping = {
|
|
63
69
|
ThinkingLevel.NONE: None,
|
|
64
|
-
ThinkingLevel.LOW: "
|
|
70
|
+
ThinkingLevel.LOW: "low",
|
|
65
71
|
ThinkingLevel.MEDIUM: "high",
|
|
66
72
|
ThinkingLevel.HIGH: "high",
|
|
67
|
-
ThinkingLevel.XHIGH: "
|
|
73
|
+
ThinkingLevel.XHIGH: "high",
|
|
74
|
+
ThinkingLevel.MAX: "max",
|
|
68
75
|
}
|
|
69
76
|
return mapping[thinking_level]
|
|
70
77
|
|
|
@@ -206,7 +213,9 @@ class DeepSeekV4Client(LLMClient):
|
|
|
206
213
|
usage_metadata: UsageMetadata | None = None
|
|
207
214
|
finish_reason: FinishReason | None = None
|
|
208
215
|
|
|
209
|
-
|
|
216
|
+
# gateways inject content-free heartbeat chunks on long generations, whose choices
|
|
217
|
+
# the SDK leaves as None rather than an empty list
|
|
218
|
+
if model_output.choices:
|
|
210
219
|
choice = model_output.choices[0]
|
|
211
220
|
delta = choice.delta
|
|
212
221
|
|
|
@@ -142,6 +142,8 @@ class Gemini3_7Client(LLMClient):
|
|
|
142
142
|
ThinkingLevel.MEDIUM: types.ThinkingLevel.MEDIUM,
|
|
143
143
|
ThinkingLevel.HIGH: types.ThinkingLevel.HIGH,
|
|
144
144
|
ThinkingLevel.XHIGH: types.ThinkingLevel.HIGH,
|
|
145
|
+
# Gemini stops at "high", so both top levels land there before per-model clamping
|
|
146
|
+
ThinkingLevel.MAX: types.ThinkingLevel.HIGH,
|
|
145
147
|
}
|
|
146
148
|
level = mapping.get(thinking_level)
|
|
147
149
|
if level is None:
|
|
@@ -201,6 +203,8 @@ class Gemini3_7Client(LLMClient):
|
|
|
201
203
|
"sampling parameters starting with the 3.6 generation.",
|
|
202
204
|
)
|
|
203
205
|
|
|
206
|
+
# include_thoughts asks for thought summaries, but whether generateContent returns any
|
|
207
|
+
# is model-dependent (llmsdk_docs/gemini3_7/docs/thinking.md)
|
|
204
208
|
thinking_summary = config.get("thinking_summary")
|
|
205
209
|
thinking_level = config.get("thinking_level")
|
|
206
210
|
if thinking_summary is not None or thinking_level is not None:
|
|
@@ -436,6 +440,11 @@ class Gemini3_7Client(LLMClient):
|
|
|
436
440
|
"response_tokens": model_output.usage_metadata.candidates_token_count,
|
|
437
441
|
}
|
|
438
442
|
|
|
443
|
+
if not content_items and usage_metadata is None and finish_reason is None:
|
|
444
|
+
# nothing was read out of the chunk, so there is nothing to emit: a gateway
|
|
445
|
+
# heartbeat looks like this, and so does any other chunk we take no value from
|
|
446
|
+
event_type = "unused"
|
|
447
|
+
|
|
439
448
|
return {
|
|
440
449
|
"role": "assistant",
|
|
441
450
|
"event_type": event_type,
|
|
@@ -511,6 +520,9 @@ class Gemini3_7Client(LLMClient):
|
|
|
511
520
|
)
|
|
512
521
|
async for chunk in response_stream:
|
|
513
522
|
event = self.transform_model_output_to_uni_event(chunk)
|
|
523
|
+
if event["event_type"] == "unused":
|
|
524
|
+
continue
|
|
525
|
+
|
|
514
526
|
for item in event["content_items"]:
|
|
515
527
|
if item["type"] == "tool_call":
|
|
516
528
|
# gemini 3.7 does not support partial tool call, mock a partial tool call event
|
|
@@ -81,6 +81,7 @@ class GLM5_3Client(LLMClient):
|
|
|
81
81
|
ThinkingLevel.MEDIUM: "high",
|
|
82
82
|
ThinkingLevel.HIGH: "high",
|
|
83
83
|
ThinkingLevel.XHIGH: "max",
|
|
84
|
+
ThinkingLevel.MAX: "max",
|
|
84
85
|
}
|
|
85
86
|
return mapping.get(thinking_level)
|
|
86
87
|
if "glm-5.2" in model:
|
|
@@ -90,6 +91,7 @@ class GLM5_3Client(LLMClient):
|
|
|
90
91
|
ThinkingLevel.MEDIUM: "medium",
|
|
91
92
|
ThinkingLevel.HIGH: "high",
|
|
92
93
|
ThinkingLevel.XHIGH: "xhigh",
|
|
94
|
+
ThinkingLevel.MAX: "max",
|
|
93
95
|
}
|
|
94
96
|
return mapping.get(thinking_level)
|
|
95
97
|
return None
|
|
@@ -239,7 +241,9 @@ class GLM5_3Client(LLMClient):
|
|
|
239
241
|
usage_metadata: UsageMetadata | None = None
|
|
240
242
|
finish_reason: FinishReason | None = None
|
|
241
243
|
|
|
242
|
-
|
|
244
|
+
# gateways inject content-free heartbeat chunks on long generations, whose choices
|
|
245
|
+
# the SDK leaves as None rather than an empty list
|
|
246
|
+
if model_output.choices:
|
|
243
247
|
choice = model_output.choices[0]
|
|
244
248
|
delta = choice.delta
|
|
245
249
|
|
|
@@ -54,6 +54,7 @@ class GPT5_6Client(LLMClient):
|
|
|
54
54
|
ThinkingLevel.MEDIUM: "medium",
|
|
55
55
|
ThinkingLevel.HIGH: "high",
|
|
56
56
|
ThinkingLevel.XHIGH: "xhigh",
|
|
57
|
+
ThinkingLevel.MAX: "max",
|
|
57
58
|
}
|
|
58
59
|
return mapping.get(thinking_level)
|
|
59
60
|
|
|
@@ -301,6 +302,7 @@ class GPT5_6Client(LLMClient):
|
|
|
301
302
|
"response.reasoning_text.done",
|
|
302
303
|
"response.content_part.added",
|
|
303
304
|
"response.content_part.done",
|
|
305
|
+
"keepalive", # gateway heartbeat on long generations; carries no content
|
|
304
306
|
]:
|
|
305
307
|
event_type = "unused"
|
|
306
308
|
|
|
@@ -286,7 +286,8 @@ def create_chat_app() -> Flask:
|
|
|
286
286
|
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="low" data-label="Low" data-description="Low thinking budget" onclick="selectComboboxOption('thinkingLevelCombobox', this)">Low</button>
|
|
287
287
|
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="medium" data-label="Medium" data-description="Medium thinking budget" onclick="selectComboboxOption('thinkingLevelCombobox', this)">Medium</button>
|
|
288
288
|
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="high" data-label="High" data-description="High thinking budget" onclick="selectComboboxOption('thinkingLevelCombobox', this)">High</button>
|
|
289
|
-
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="xhigh" data-label="XHigh" data-description="
|
|
289
|
+
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="xhigh" data-label="XHigh" data-description="Extended thinking budget" onclick="selectComboboxOption('thinkingLevelCombobox', this)">XHigh</button>
|
|
290
|
+
<button type="button" role="option" aria-selected="false" class="w-full px-3 py-2 text-left hover:bg-gray-50 focus:bg-gray-50 focus:outline-none" data-combobox-option data-value="max" data-label="Max" data-description="Maximum thinking budget" onclick="selectComboboxOption('thinkingLevelCombobox', this)">Max</button>
|
|
290
291
|
</div>
|
|
291
292
|
</div>
|
|
292
293
|
</div>
|
|
@@ -78,6 +78,7 @@ class KimiK3Client(LLMClient):
|
|
|
78
78
|
ThinkingLevel.MEDIUM: {"type": "enabled", "keep": "all"},
|
|
79
79
|
ThinkingLevel.HIGH: {"type": "enabled", "keep": "all"},
|
|
80
80
|
ThinkingLevel.XHIGH: {"type": "enabled", "keep": "all"},
|
|
81
|
+
ThinkingLevel.MAX: {"type": "enabled", "keep": "all"},
|
|
81
82
|
}
|
|
82
83
|
return mapping.get(thinking_level)
|
|
83
84
|
|
|
@@ -92,6 +93,7 @@ class KimiK3Client(LLMClient):
|
|
|
92
93
|
ThinkingLevel.MEDIUM: "high",
|
|
93
94
|
ThinkingLevel.HIGH: "high",
|
|
94
95
|
ThinkingLevel.XHIGH: "max",
|
|
96
|
+
ThinkingLevel.MAX: "max",
|
|
95
97
|
}
|
|
96
98
|
return mapping.get(thinking_level)
|
|
97
99
|
|
|
@@ -267,7 +269,9 @@ class KimiK3Client(LLMClient):
|
|
|
267
269
|
usage_metadata: UsageMetadata | None = None
|
|
268
270
|
finish_reason: FinishReason | None = None
|
|
269
271
|
|
|
270
|
-
|
|
272
|
+
# gateways inject content-free heartbeat chunks on long generations, whose choices
|
|
273
|
+
# the SDK leaves as None rather than an empty list
|
|
274
|
+
if model_output.choices:
|
|
271
275
|
choice = model_output.choices[0]
|
|
272
276
|
delta = choice.delta
|
|
273
277
|
|
|
@@ -63,6 +63,8 @@ class MiniMaxM3Client(LLMClient):
|
|
|
63
63
|
ThinkingLevel.MEDIUM: "medium",
|
|
64
64
|
ThinkingLevel.HIGH: "high",
|
|
65
65
|
ThinkingLevel.XHIGH: "high",
|
|
66
|
+
# MiniMax stops at "high"
|
|
67
|
+
ThinkingLevel.MAX: "high",
|
|
66
68
|
}
|
|
67
69
|
return mapping[thinking_level]
|
|
68
70
|
|
|
@@ -248,6 +250,7 @@ class MiniMaxM3Client(LLMClient):
|
|
|
248
250
|
"response.output_item.done",
|
|
249
251
|
"response.content_part.added",
|
|
250
252
|
"response.content_part.done",
|
|
253
|
+
"keepalive", # gateway heartbeat on long generations; carries no content
|
|
251
254
|
):
|
|
252
255
|
raise ValueError(f"Unknown output: {model_output}")
|
|
253
256
|
|
|
@@ -220,7 +220,9 @@ class OpenaiChatClient(LLMClient):
|
|
|
220
220
|
usage_metadata: UsageMetadata | None = None
|
|
221
221
|
finish_reason: FinishReason | None = None
|
|
222
222
|
|
|
223
|
-
|
|
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
|
|
|
@@ -54,6 +54,7 @@ class OpenaiResponsesClient(LLMClient):
|
|
|
54
54
|
ThinkingLevel.MEDIUM: "medium",
|
|
55
55
|
ThinkingLevel.HIGH: "high",
|
|
56
56
|
ThinkingLevel.XHIGH: "xhigh",
|
|
57
|
+
ThinkingLevel.MAX: "max",
|
|
57
58
|
}
|
|
58
59
|
return mapping.get(thinking_level)
|
|
59
60
|
|
|
@@ -298,6 +299,7 @@ class OpenaiResponsesClient(LLMClient):
|
|
|
298
299
|
"response.reasoning_summary_text.done",
|
|
299
300
|
"response.content_part.added",
|
|
300
301
|
"response.content_part.done",
|
|
302
|
+
"keepalive", # gateway heartbeat on long generations; carries no content
|
|
301
303
|
):
|
|
302
304
|
event_type = "unused"
|
|
303
305
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "agenthub-python"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.4"
|
|
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.
|
|
3
|
+
version = "0.4.4"
|
|
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"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|