agenthub-python 0.3.0__tar.gz → 0.3.2__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.3.2/PKG-INFO +351 -0
- agenthub_python-0.3.2/README.md +330 -0
- agenthub_python-0.3.2/agenthub/abort_signal.py +135 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/auto_client.py +34 -15
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/base_client.py +96 -13
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/claude4_6/client.py +28 -14
- agenthub_python-0.3.2/agenthub/claude4_8/__init__.py +18 -0
- agenthub_python-0.3.2/agenthub/claude4_8/client.py +429 -0
- agenthub_python-0.3.2/agenthub/deepseek_v4/__init__.py +18 -0
- agenthub_python-0.3.2/agenthub/deepseek_v4/client.py +337 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/gemini3/client.py +117 -2
- {agenthub_python-0.3.0/agenthub/qwen3 → agenthub_python-0.3.2/agenthub/glm5_1}/__init__.py +2 -2
- {agenthub_python-0.3.0/agenthub/glm5 → agenthub_python-0.3.2/agenthub/glm5_1}/client.py +13 -12
- {agenthub_python-0.3.0/agenthub/gpt5_4 → agenthub_python-0.3.2/agenthub/gpt5_5}/__init__.py +2 -2
- {agenthub_python-0.3.0/agenthub/gpt5_4 → agenthub_python-0.3.2/agenthub/gpt5_5}/client.py +18 -18
- agenthub_python-0.3.2/agenthub/integration/playground.py +1192 -0
- agenthub_python-0.3.2/agenthub/integration/tracer.py +786 -0
- {agenthub_python-0.3.0/agenthub/kimi_k2_5 → agenthub_python-0.3.2/agenthub/kimi_k2_6}/__init__.py +2 -2
- {agenthub_python-0.3.0/agenthub/kimi_k2_5 → agenthub_python-0.3.2/agenthub/kimi_k2_6}/client.py +14 -13
- {agenthub_python-0.3.0/agenthub/glm5 → agenthub_python-0.3.2/agenthub/openai}/__init__.py +2 -2
- {agenthub_python-0.3.0/agenthub/qwen3 → agenthub_python-0.3.2/agenthub/openai}/client.py +92 -95
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/types.py +57 -1
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/pyproject.toml +10 -4
- agenthub_python-0.3.0/PKG-INFO +0 -10
- agenthub_python-0.3.0/agenthub/integration/playground.py +0 -646
- agenthub_python-0.3.0/agenthub/integration/tracer.py +0 -528
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/__init__.py +0 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/claude4_6/__init__.py +0 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/gemini3/__init__.py +0 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/integration/__init__.py +0 -0
- {agenthub_python-0.3.0 → agenthub_python-0.3.2}/agenthub/utils.py +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agenthub-python
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: AgentHub is the LLM API Hub for the Agent era, built for high-precision autonomous agents.
|
|
5
|
+
Keywords: agent,llm,gemini,claude,gpt
|
|
6
|
+
Author: PrismShadow
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Requires-Dist: google-genai>=1.70.0
|
|
9
|
+
Requires-Dist: anthropic[bedrock]>=0.87.0
|
|
10
|
+
Requires-Dist: flask>=3.0.0
|
|
11
|
+
Requires-Dist: openai>=2.30.0
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
Requires-Dist: httpx[socks] ; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest>=8.4.2 ; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.23.0 ; extra == 'dev'
|
|
16
|
+
Requires-Dist: ruff>=0.14.3 ; extra == 'dev'
|
|
17
|
+
Requires-Dist: pillow>=10.0.0 ; extra == 'dev'
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# AgentHub Python Implementation
|
|
23
|
+
|
|
24
|
+
This document demonstrates how to use `AutoLLMClient` for unified LLM interactions in AgentHub.
|
|
25
|
+
|
|
26
|
+
## Building
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
make install # Install dependencies
|
|
30
|
+
make build # Build Python package
|
|
31
|
+
make lint # Run ruff linter
|
|
32
|
+
make test # Run tests
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## AutoLLMClient Overview
|
|
36
|
+
|
|
37
|
+
`AutoLLMClient` is a stateful client that automatically routes requests to the appropriate model-specific implementation. It maintains conversation history and provides a unified interface for different LLM providers.
|
|
38
|
+
|
|
39
|
+
### Initialization
|
|
40
|
+
|
|
41
|
+
Create a client by specifying the model name:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from agenthub import AutoLLMClient
|
|
45
|
+
|
|
46
|
+
# Initialize with model name
|
|
47
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
48
|
+
|
|
49
|
+
# Optionally specify API key (if not using environment variables)
|
|
50
|
+
client = AutoLLMClient(model="gpt-5.5", api_key="your-openai-api-key")
|
|
51
|
+
|
|
52
|
+
# Use OpenAI Chat Completions-compatible routing explicitly
|
|
53
|
+
client = AutoLLMClient(model="custom-model", client_type="openai")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The client automatically selects the appropriate client based on the model name.
|
|
57
|
+
|
|
58
|
+
## Core Methods
|
|
59
|
+
|
|
60
|
+
### streaming_response
|
|
61
|
+
|
|
62
|
+
Stateless method that requires passing the full message history on each call:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import asyncio
|
|
66
|
+
from agenthub import AutoLLMClient
|
|
67
|
+
|
|
68
|
+
async def main():
|
|
69
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
70
|
+
|
|
71
|
+
async for event in client.streaming_response(
|
|
72
|
+
messages=[
|
|
73
|
+
{
|
|
74
|
+
"role": "user",
|
|
75
|
+
"content_items": [{"type": "text", "text": "Hello!"}]
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
config={}
|
|
79
|
+
):
|
|
80
|
+
print(event)
|
|
81
|
+
|
|
82
|
+
asyncio.run(main())
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### streaming_response_stateful
|
|
86
|
+
|
|
87
|
+
Stateful method that maintains conversation history internally:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import asyncio
|
|
91
|
+
from agenthub import AutoLLMClient
|
|
92
|
+
|
|
93
|
+
async def main():
|
|
94
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
95
|
+
|
|
96
|
+
# First message
|
|
97
|
+
async for event in client.streaming_response_stateful(
|
|
98
|
+
message={
|
|
99
|
+
"role": "user",
|
|
100
|
+
"content_items": [{"type": "text", "text": "My name is Alice"}]
|
|
101
|
+
},
|
|
102
|
+
config={}
|
|
103
|
+
):
|
|
104
|
+
print(event)
|
|
105
|
+
|
|
106
|
+
# Second message - history is maintained automatically
|
|
107
|
+
async for event in client.streaming_response_stateful(
|
|
108
|
+
message={
|
|
109
|
+
"role": "user",
|
|
110
|
+
"content_items": [{"type": "text", "text": "What's my name?"}]
|
|
111
|
+
},
|
|
112
|
+
config={}
|
|
113
|
+
):
|
|
114
|
+
print(event)
|
|
115
|
+
|
|
116
|
+
asyncio.run(main())
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### get_history
|
|
120
|
+
|
|
121
|
+
Retrieve the conversation history:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
# Get all messages in the conversation
|
|
125
|
+
history = client.get_history()
|
|
126
|
+
print(f"Total messages: {len(history)}")
|
|
127
|
+
|
|
128
|
+
for msg in history:
|
|
129
|
+
print(f"Role: {msg['role']}")
|
|
130
|
+
print(f"Content: {msg['content_items']}")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### clear_history
|
|
134
|
+
|
|
135
|
+
Clear the conversation history:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
# Clear all conversation history
|
|
139
|
+
client.clear_history()
|
|
140
|
+
|
|
141
|
+
# Verify history is empty
|
|
142
|
+
assert len(client.get_history()) == 0
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### set_history
|
|
146
|
+
|
|
147
|
+
Replace the conversation history with a copy of the provided list:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
# Save current history
|
|
151
|
+
saved_history = client.get_history()
|
|
152
|
+
|
|
153
|
+
# ... do other things, then restore
|
|
154
|
+
client.set_history(saved_history)
|
|
155
|
+
|
|
156
|
+
# Verify history was replaced
|
|
157
|
+
assert len(client.get_history()) == len(saved_history)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Tool Calling
|
|
161
|
+
|
|
162
|
+
When using tools, you must handle `tool_call_id` correctly:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
import asyncio
|
|
166
|
+
import json
|
|
167
|
+
from agenthub import AutoLLMClient
|
|
168
|
+
|
|
169
|
+
def get_weather(location: str) -> str:
|
|
170
|
+
"""Mock function to get weather."""
|
|
171
|
+
return f"Temperature in {location}: 22°C"
|
|
172
|
+
|
|
173
|
+
async def main():
|
|
174
|
+
# Define tool
|
|
175
|
+
weather_function = {
|
|
176
|
+
"name": "get_weather",
|
|
177
|
+
"description": "Gets the current weather for a given location.",
|
|
178
|
+
"parameters": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"properties": {
|
|
181
|
+
"location": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"description": "The city name"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"required": ["location"]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
191
|
+
config = {"tools": [weather_function]}
|
|
192
|
+
|
|
193
|
+
# User asks about weather
|
|
194
|
+
events = []
|
|
195
|
+
async for event in client.streaming_response_stateful(
|
|
196
|
+
message={
|
|
197
|
+
"role": "user",
|
|
198
|
+
"content_items": [{"type": "text", "text": "What's the weather in London?"}]
|
|
199
|
+
},
|
|
200
|
+
config=config
|
|
201
|
+
):
|
|
202
|
+
events.append(event)
|
|
203
|
+
|
|
204
|
+
# Extract function call and tool_call_id
|
|
205
|
+
tool_call = None
|
|
206
|
+
for event in events:
|
|
207
|
+
for item in event["content_items"]:
|
|
208
|
+
if item["type"] == "tool_call":
|
|
209
|
+
tool_call = item
|
|
210
|
+
break
|
|
211
|
+
|
|
212
|
+
if tool_call:
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
# Execute function and send result back with tool_call_id
|
|
216
|
+
if tool_call:
|
|
217
|
+
result = get_weather(**tool_call["arguments"])
|
|
218
|
+
|
|
219
|
+
# IMPORTANT: Include tool_call_id in the tool response
|
|
220
|
+
async for event in client.streaming_response_stateful(
|
|
221
|
+
message={
|
|
222
|
+
"role": "user",
|
|
223
|
+
"content_items": [
|
|
224
|
+
{
|
|
225
|
+
"type": "tool_result",
|
|
226
|
+
"text": result,
|
|
227
|
+
"tool_call_id": tool_call["tool_call_id"] # Required for tool responses
|
|
228
|
+
}
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
config=config
|
|
232
|
+
):
|
|
233
|
+
print(event)
|
|
234
|
+
|
|
235
|
+
asyncio.run(main())
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Message Format
|
|
239
|
+
|
|
240
|
+
### UniMessage Structure
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
{
|
|
244
|
+
"role": "user" | "assistant",
|
|
245
|
+
"content_items": [
|
|
246
|
+
{"type": "text", "text": "Hello"},
|
|
247
|
+
{"type": "image_url", "image_url": "https://..."},
|
|
248
|
+
{"type": "tool_call", "name": "get_weather", "arguments": {"location": "London"}, "tool_call_id": "call_abc123"}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Tool Response with tool_call_id
|
|
254
|
+
|
|
255
|
+
When responding to a tool call, include the `tool_call_id` in the result content item:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
{
|
|
259
|
+
"role": "user",
|
|
260
|
+
"content_items": [
|
|
261
|
+
{
|
|
262
|
+
"type": "tool_result",
|
|
263
|
+
"text": "London is 22°C today.",
|
|
264
|
+
"tool_call_id": "call_abc123" # From tool_call event
|
|
265
|
+
}
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Configuration Options
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
from agenthub import PromptCaching, ThinkingLevel
|
|
274
|
+
|
|
275
|
+
config = {
|
|
276
|
+
"max_tokens": 500,
|
|
277
|
+
"temperature": 1.0,
|
|
278
|
+
"tools": [tool_definition],
|
|
279
|
+
"thinking_summary": True,
|
|
280
|
+
"thinking_level": ThinkingLevel.HIGH,
|
|
281
|
+
"tool_choice": "auto", # "auto", "required", "none", or ["tool_name"]
|
|
282
|
+
"system_prompt": "You are a helpful assistant",
|
|
283
|
+
"prompt_caching": PromptCaching.ENABLE,
|
|
284
|
+
"trace_id": "agent1/conversation_001" # Optional: save conversation trace
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Conversation Tracing
|
|
289
|
+
|
|
290
|
+
AgentHub provides a built-in `Tracer` to save and browse conversation history. When you specify a `trace_id` in the config, conversations are automatically saved to both JSON and TXT formats.
|
|
291
|
+
|
|
292
|
+
### Basic Usage
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from agenthub import AutoLLMClient
|
|
296
|
+
|
|
297
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
298
|
+
|
|
299
|
+
# Add trace_id to config
|
|
300
|
+
config = {"trace_id": "agent1/conversation_001"}
|
|
301
|
+
|
|
302
|
+
async for event in client.streaming_response_stateful(
|
|
303
|
+
message={"role": "user", "content_items": [{"type": "text", "text": "Hello"}]},
|
|
304
|
+
config=config
|
|
305
|
+
):
|
|
306
|
+
pass # Conversation is automatically saved
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
The default cache directory is `cache`, you can change it by setting `AGENTHUB_CACHE_DIR` environment variable.
|
|
310
|
+
|
|
311
|
+
This creates two files in the `cache` directory:
|
|
312
|
+
- `cache/agent1/conversation_001.json` - Structured data with full history and config
|
|
313
|
+
- `cache/agent1/conversation_001.txt` - Human-readable conversation format
|
|
314
|
+
|
|
315
|
+
### Browsing Traces with Web Interface
|
|
316
|
+
|
|
317
|
+
Start a web server to browse and view saved conversations:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from agenthub.integration.tracer import Tracer
|
|
321
|
+
|
|
322
|
+
# Start web server
|
|
323
|
+
Tracer("path/to/cache").start_web_server(host="127.0.0.1", port=25750)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Or use the CLI:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
python -m agenthub.integration.tracer --cache_dir ./cache --host 127.0.0.1 --port 25750
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Then visit `http://127.0.0.1:25750` in your browser to browse saved conversations.
|
|
333
|
+
|
|
334
|
+
### Test with Playground
|
|
335
|
+
|
|
336
|
+
Start a web server to test with the playground:
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
from agenthub.integration.playground import start_playground_server
|
|
340
|
+
|
|
341
|
+
start_playground_server()
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Or use the CLI:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
python -m agenthub.integration.playground --host 127.0.0.1 --port 25751
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Then visit `http://127.0.0.1:25751` in your browser to test with the playground.
|
|
351
|
+
The integrated tracer is available at `http://127.0.0.1:25751/tracer/`.
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# AgentHub Python Implementation
|
|
2
|
+
|
|
3
|
+
This document demonstrates how to use `AutoLLMClient` for unified LLM interactions in AgentHub.
|
|
4
|
+
|
|
5
|
+
## Building
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
make install # Install dependencies
|
|
9
|
+
make build # Build Python package
|
|
10
|
+
make lint # Run ruff linter
|
|
11
|
+
make test # Run tests
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## AutoLLMClient Overview
|
|
15
|
+
|
|
16
|
+
`AutoLLMClient` is a stateful client that automatically routes requests to the appropriate model-specific implementation. It maintains conversation history and provides a unified interface for different LLM providers.
|
|
17
|
+
|
|
18
|
+
### Initialization
|
|
19
|
+
|
|
20
|
+
Create a client by specifying the model name:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from agenthub import AutoLLMClient
|
|
24
|
+
|
|
25
|
+
# Initialize with model name
|
|
26
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
27
|
+
|
|
28
|
+
# Optionally specify API key (if not using environment variables)
|
|
29
|
+
client = AutoLLMClient(model="gpt-5.5", api_key="your-openai-api-key")
|
|
30
|
+
|
|
31
|
+
# Use OpenAI Chat Completions-compatible routing explicitly
|
|
32
|
+
client = AutoLLMClient(model="custom-model", client_type="openai")
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The client automatically selects the appropriate client based on the model name.
|
|
36
|
+
|
|
37
|
+
## Core Methods
|
|
38
|
+
|
|
39
|
+
### streaming_response
|
|
40
|
+
|
|
41
|
+
Stateless method that requires passing the full message history on each call:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import asyncio
|
|
45
|
+
from agenthub import AutoLLMClient
|
|
46
|
+
|
|
47
|
+
async def main():
|
|
48
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
49
|
+
|
|
50
|
+
async for event in client.streaming_response(
|
|
51
|
+
messages=[
|
|
52
|
+
{
|
|
53
|
+
"role": "user",
|
|
54
|
+
"content_items": [{"type": "text", "text": "Hello!"}]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
config={}
|
|
58
|
+
):
|
|
59
|
+
print(event)
|
|
60
|
+
|
|
61
|
+
asyncio.run(main())
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### streaming_response_stateful
|
|
65
|
+
|
|
66
|
+
Stateful method that maintains conversation history internally:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import asyncio
|
|
70
|
+
from agenthub import AutoLLMClient
|
|
71
|
+
|
|
72
|
+
async def main():
|
|
73
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
74
|
+
|
|
75
|
+
# First message
|
|
76
|
+
async for event in client.streaming_response_stateful(
|
|
77
|
+
message={
|
|
78
|
+
"role": "user",
|
|
79
|
+
"content_items": [{"type": "text", "text": "My name is Alice"}]
|
|
80
|
+
},
|
|
81
|
+
config={}
|
|
82
|
+
):
|
|
83
|
+
print(event)
|
|
84
|
+
|
|
85
|
+
# Second message - history is maintained automatically
|
|
86
|
+
async for event in client.streaming_response_stateful(
|
|
87
|
+
message={
|
|
88
|
+
"role": "user",
|
|
89
|
+
"content_items": [{"type": "text", "text": "What's my name?"}]
|
|
90
|
+
},
|
|
91
|
+
config={}
|
|
92
|
+
):
|
|
93
|
+
print(event)
|
|
94
|
+
|
|
95
|
+
asyncio.run(main())
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### get_history
|
|
99
|
+
|
|
100
|
+
Retrieve the conversation history:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Get all messages in the conversation
|
|
104
|
+
history = client.get_history()
|
|
105
|
+
print(f"Total messages: {len(history)}")
|
|
106
|
+
|
|
107
|
+
for msg in history:
|
|
108
|
+
print(f"Role: {msg['role']}")
|
|
109
|
+
print(f"Content: {msg['content_items']}")
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### clear_history
|
|
113
|
+
|
|
114
|
+
Clear the conversation history:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
# Clear all conversation history
|
|
118
|
+
client.clear_history()
|
|
119
|
+
|
|
120
|
+
# Verify history is empty
|
|
121
|
+
assert len(client.get_history()) == 0
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### set_history
|
|
125
|
+
|
|
126
|
+
Replace the conversation history with a copy of the provided list:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Save current history
|
|
130
|
+
saved_history = client.get_history()
|
|
131
|
+
|
|
132
|
+
# ... do other things, then restore
|
|
133
|
+
client.set_history(saved_history)
|
|
134
|
+
|
|
135
|
+
# Verify history was replaced
|
|
136
|
+
assert len(client.get_history()) == len(saved_history)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Tool Calling
|
|
140
|
+
|
|
141
|
+
When using tools, you must handle `tool_call_id` correctly:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import asyncio
|
|
145
|
+
import json
|
|
146
|
+
from agenthub import AutoLLMClient
|
|
147
|
+
|
|
148
|
+
def get_weather(location: str) -> str:
|
|
149
|
+
"""Mock function to get weather."""
|
|
150
|
+
return f"Temperature in {location}: 22°C"
|
|
151
|
+
|
|
152
|
+
async def main():
|
|
153
|
+
# Define tool
|
|
154
|
+
weather_function = {
|
|
155
|
+
"name": "get_weather",
|
|
156
|
+
"description": "Gets the current weather for a given location.",
|
|
157
|
+
"parameters": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"properties": {
|
|
160
|
+
"location": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"description": "The city name"
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
"required": ["location"]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
170
|
+
config = {"tools": [weather_function]}
|
|
171
|
+
|
|
172
|
+
# User asks about weather
|
|
173
|
+
events = []
|
|
174
|
+
async for event in client.streaming_response_stateful(
|
|
175
|
+
message={
|
|
176
|
+
"role": "user",
|
|
177
|
+
"content_items": [{"type": "text", "text": "What's the weather in London?"}]
|
|
178
|
+
},
|
|
179
|
+
config=config
|
|
180
|
+
):
|
|
181
|
+
events.append(event)
|
|
182
|
+
|
|
183
|
+
# Extract function call and tool_call_id
|
|
184
|
+
tool_call = None
|
|
185
|
+
for event in events:
|
|
186
|
+
for item in event["content_items"]:
|
|
187
|
+
if item["type"] == "tool_call":
|
|
188
|
+
tool_call = item
|
|
189
|
+
break
|
|
190
|
+
|
|
191
|
+
if tool_call:
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
# Execute function and send result back with tool_call_id
|
|
195
|
+
if tool_call:
|
|
196
|
+
result = get_weather(**tool_call["arguments"])
|
|
197
|
+
|
|
198
|
+
# IMPORTANT: Include tool_call_id in the tool response
|
|
199
|
+
async for event in client.streaming_response_stateful(
|
|
200
|
+
message={
|
|
201
|
+
"role": "user",
|
|
202
|
+
"content_items": [
|
|
203
|
+
{
|
|
204
|
+
"type": "tool_result",
|
|
205
|
+
"text": result,
|
|
206
|
+
"tool_call_id": tool_call["tool_call_id"] # Required for tool responses
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
config=config
|
|
211
|
+
):
|
|
212
|
+
print(event)
|
|
213
|
+
|
|
214
|
+
asyncio.run(main())
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Message Format
|
|
218
|
+
|
|
219
|
+
### UniMessage Structure
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
{
|
|
223
|
+
"role": "user" | "assistant",
|
|
224
|
+
"content_items": [
|
|
225
|
+
{"type": "text", "text": "Hello"},
|
|
226
|
+
{"type": "image_url", "image_url": "https://..."},
|
|
227
|
+
{"type": "tool_call", "name": "get_weather", "arguments": {"location": "London"}, "tool_call_id": "call_abc123"}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Tool Response with tool_call_id
|
|
233
|
+
|
|
234
|
+
When responding to a tool call, include the `tool_call_id` in the result content item:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
{
|
|
238
|
+
"role": "user",
|
|
239
|
+
"content_items": [
|
|
240
|
+
{
|
|
241
|
+
"type": "tool_result",
|
|
242
|
+
"text": "London is 22°C today.",
|
|
243
|
+
"tool_call_id": "call_abc123" # From tool_call event
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Configuration Options
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from agenthub import PromptCaching, ThinkingLevel
|
|
253
|
+
|
|
254
|
+
config = {
|
|
255
|
+
"max_tokens": 500,
|
|
256
|
+
"temperature": 1.0,
|
|
257
|
+
"tools": [tool_definition],
|
|
258
|
+
"thinking_summary": True,
|
|
259
|
+
"thinking_level": ThinkingLevel.HIGH,
|
|
260
|
+
"tool_choice": "auto", # "auto", "required", "none", or ["tool_name"]
|
|
261
|
+
"system_prompt": "You are a helpful assistant",
|
|
262
|
+
"prompt_caching": PromptCaching.ENABLE,
|
|
263
|
+
"trace_id": "agent1/conversation_001" # Optional: save conversation trace
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Conversation Tracing
|
|
268
|
+
|
|
269
|
+
AgentHub provides a built-in `Tracer` to save and browse conversation history. When you specify a `trace_id` in the config, conversations are automatically saved to both JSON and TXT formats.
|
|
270
|
+
|
|
271
|
+
### Basic Usage
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from agenthub import AutoLLMClient
|
|
275
|
+
|
|
276
|
+
client = AutoLLMClient(model="gpt-5.5")
|
|
277
|
+
|
|
278
|
+
# Add trace_id to config
|
|
279
|
+
config = {"trace_id": "agent1/conversation_001"}
|
|
280
|
+
|
|
281
|
+
async for event in client.streaming_response_stateful(
|
|
282
|
+
message={"role": "user", "content_items": [{"type": "text", "text": "Hello"}]},
|
|
283
|
+
config=config
|
|
284
|
+
):
|
|
285
|
+
pass # Conversation is automatically saved
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The default cache directory is `cache`, you can change it by setting `AGENTHUB_CACHE_DIR` environment variable.
|
|
289
|
+
|
|
290
|
+
This creates two files in the `cache` directory:
|
|
291
|
+
- `cache/agent1/conversation_001.json` - Structured data with full history and config
|
|
292
|
+
- `cache/agent1/conversation_001.txt` - Human-readable conversation format
|
|
293
|
+
|
|
294
|
+
### Browsing Traces with Web Interface
|
|
295
|
+
|
|
296
|
+
Start a web server to browse and view saved conversations:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
from agenthub.integration.tracer import Tracer
|
|
300
|
+
|
|
301
|
+
# Start web server
|
|
302
|
+
Tracer("path/to/cache").start_web_server(host="127.0.0.1", port=25750)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Or use the CLI:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
python -m agenthub.integration.tracer --cache_dir ./cache --host 127.0.0.1 --port 25750
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Then visit `http://127.0.0.1:25750` in your browser to browse saved conversations.
|
|
312
|
+
|
|
313
|
+
### Test with Playground
|
|
314
|
+
|
|
315
|
+
Start a web server to test with the playground:
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
from agenthub.integration.playground import start_playground_server
|
|
319
|
+
|
|
320
|
+
start_playground_server()
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Or use the CLI:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
python -m agenthub.integration.playground --host 127.0.0.1 --port 25751
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Then visit `http://127.0.0.1:25751` in your browser to test with the playground.
|
|
330
|
+
The integrated tracer is available at `http://127.0.0.1:25751/tracer/`.
|