hivetrace 1.3.8__tar.gz → 1.3.10__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.
- {hivetrace-1.3.8 → hivetrace-1.3.10}/PKG-INFO +81 -12
- {hivetrace-1.3.8 → hivetrace-1.3.10}/README.md +80 -11
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/client/async_client.py +66 -4
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/client/base.py +53 -1
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/client/sync_client.py +68 -3
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/models/requests.py +3 -3
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/models/responses.py +4 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace.egg-info/PKG-INFO +81 -12
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace.egg-info/requires.txt +3 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/setup.py +2 -1
- {hivetrace-1.3.8 → hivetrace-1.3.10}/LICENSE +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/base_adapter.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/adapter.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/decorators.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/monitored_agent.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/monitored_crew.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/crewai/tool_wrapper.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/adapter.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/api.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/behavior_tracker.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/callback.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/decorators.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/langchain/models.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/openai_agents/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/openai_agents/adapter.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/openai_agents/models.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/openai_agents/tracing.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/utils/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/adapters/utils/logging.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/client/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/errors/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/errors/api.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/errors/base.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/errors/network.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/errors/validation.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/handlers/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/handlers/error_handler.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/handlers/response_builder.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/models/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/utils/__init__.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/utils/error_helpers.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace/utils/uuid_generator.py +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace.egg-info/SOURCES.txt +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace.egg-info/dependency_links.txt +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/hivetrace.egg-info/top_level.txt +0 -0
- {hivetrace-1.3.8 → hivetrace-1.3.10}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hivetrace
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.10
|
|
4
4
|
Summary: Hivetrace SDK for monitoring LLM applications
|
|
5
5
|
Home-page: http://hivetrace.ai
|
|
6
6
|
Author: Raft
|
|
@@ -60,6 +60,16 @@ response = client.input(
|
|
|
60
60
|
application_id="your-application-id", # Obtained after registering the application in the UI
|
|
61
61
|
message="User prompt here",
|
|
62
62
|
)
|
|
63
|
+
|
|
64
|
+
# Optionally attach files (filename, bytes, mime_type)
|
|
65
|
+
files = [
|
|
66
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
67
|
+
]
|
|
68
|
+
response_with_files = client.input(
|
|
69
|
+
application_id="your-application-id",
|
|
70
|
+
message="User prompt with files",
|
|
71
|
+
files=files,
|
|
72
|
+
)
|
|
63
73
|
```
|
|
64
74
|
|
|
65
75
|
### Send an LLM response (output)
|
|
@@ -69,6 +79,16 @@ response = client.output(
|
|
|
69
79
|
application_id="your-application-id",
|
|
70
80
|
message="LLM response here",
|
|
71
81
|
)
|
|
82
|
+
|
|
83
|
+
# With files
|
|
84
|
+
files = [
|
|
85
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
86
|
+
]
|
|
87
|
+
response_with_files = client.output(
|
|
88
|
+
application_id="your-application-id",
|
|
89
|
+
message="LLM response with files",
|
|
90
|
+
files=files,
|
|
91
|
+
)
|
|
72
92
|
```
|
|
73
93
|
|
|
74
94
|
---
|
|
@@ -89,6 +109,16 @@ response = await client.input(
|
|
|
89
109
|
application_id="your-application-id",
|
|
90
110
|
message="User prompt here",
|
|
91
111
|
)
|
|
112
|
+
|
|
113
|
+
# With files (filename, bytes, mime_type)
|
|
114
|
+
files = [
|
|
115
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
116
|
+
]
|
|
117
|
+
response_with_files = await client.input(
|
|
118
|
+
application_id="your-application-id",
|
|
119
|
+
message="User prompt with files",
|
|
120
|
+
files=files,
|
|
121
|
+
)
|
|
92
122
|
```
|
|
93
123
|
|
|
94
124
|
### Send an LLM response (output)
|
|
@@ -98,6 +128,16 @@ response = await client.output(
|
|
|
98
128
|
application_id="your-application-id",
|
|
99
129
|
message="LLM response here",
|
|
100
130
|
)
|
|
131
|
+
|
|
132
|
+
# With files
|
|
133
|
+
files = [
|
|
134
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
135
|
+
]
|
|
136
|
+
response_with_files = await client.output(
|
|
137
|
+
application_id="your-application-id",
|
|
138
|
+
message="LLM response with files",
|
|
139
|
+
files=files,
|
|
140
|
+
)
|
|
101
141
|
```
|
|
102
142
|
|
|
103
143
|
---
|
|
@@ -115,13 +155,13 @@ response = client.input(
|
|
|
115
155
|
"agent-1-id": {"name": "Agent 1", "description": "Agent description"},
|
|
116
156
|
"agent-2-id": {"name": "Agent 2"},
|
|
117
157
|
"agent-3-id": {}
|
|
118
|
-
}
|
|
158
|
+
},
|
|
159
|
+
# If you want to send only to censor and avoid DB persistence on backend
|
|
160
|
+
"censor_only": True,
|
|
119
161
|
}
|
|
120
162
|
)
|
|
121
163
|
```
|
|
122
164
|
|
|
123
|
-
> **Note:** `session_id`, `user_id`, and all agent IDs must be valid UUIDs.
|
|
124
|
-
|
|
125
165
|
---
|
|
126
166
|
|
|
127
167
|
## API
|
|
@@ -130,10 +170,20 @@ response = client.input(
|
|
|
130
170
|
|
|
131
171
|
```python
|
|
132
172
|
# Sync
|
|
133
|
-
def input(
|
|
173
|
+
def input(
|
|
174
|
+
application_id: str,
|
|
175
|
+
message: str,
|
|
176
|
+
additional_parameters: dict | None = None,
|
|
177
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
178
|
+
) -> dict: ...
|
|
134
179
|
|
|
135
180
|
# Async
|
|
136
|
-
async def input(
|
|
181
|
+
async def input(
|
|
182
|
+
application_id: str,
|
|
183
|
+
message: str,
|
|
184
|
+
additional_parameters: dict | None = None,
|
|
185
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
186
|
+
) -> dict: ...
|
|
137
187
|
```
|
|
138
188
|
|
|
139
189
|
Sends a **user prompt** to Hivetrace.
|
|
@@ -141,18 +191,22 @@ Sends a **user prompt** to Hivetrace.
|
|
|
141
191
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
142
192
|
* `message` — The user prompt
|
|
143
193
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
194
|
+
- Supported special flags: `censor_only: bool` — when `True`, backend should not persist the message in DB and only pass it to the censor
|
|
195
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`; files are attached to the created analysis record
|
|
196
|
+
|
|
197
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
144
198
|
|
|
145
199
|
**Response example:**
|
|
146
200
|
|
|
147
201
|
```json
|
|
148
202
|
{
|
|
203
|
+
"blocked": false,
|
|
149
204
|
"status": "processed",
|
|
150
205
|
"monitoring_result": {
|
|
151
206
|
"is_toxic": false,
|
|
152
207
|
"type_of_violation": "benign",
|
|
153
208
|
"token_count": 9,
|
|
154
|
-
"
|
|
155
|
-
"token_usage_unbounded": false
|
|
209
|
+
"token_usage_severity": None
|
|
156
210
|
}
|
|
157
211
|
}
|
|
158
212
|
```
|
|
@@ -163,10 +217,20 @@ Sends a **user prompt** to Hivetrace.
|
|
|
163
217
|
|
|
164
218
|
```python
|
|
165
219
|
# Sync
|
|
166
|
-
def output(
|
|
220
|
+
def output(
|
|
221
|
+
application_id: str,
|
|
222
|
+
message: str,
|
|
223
|
+
additional_parameters: dict | None = None,
|
|
224
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
225
|
+
) -> dict: ...
|
|
167
226
|
|
|
168
227
|
# Async
|
|
169
|
-
async def output(
|
|
228
|
+
async def output(
|
|
229
|
+
application_id: str,
|
|
230
|
+
message: str,
|
|
231
|
+
additional_parameters: dict | None = None,
|
|
232
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
233
|
+
) -> dict: ...
|
|
170
234
|
```
|
|
171
235
|
|
|
172
236
|
Sends an **LLM response** to Hivetrace.
|
|
@@ -174,18 +238,23 @@ Sends an **LLM response** to Hivetrace.
|
|
|
174
238
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
175
239
|
* `message` — The LLM response
|
|
176
240
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
241
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`
|
|
242
|
+
|
|
243
|
+
> Files are uploaded after the main request completes and an analysis ID is available.
|
|
244
|
+
|
|
245
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
177
246
|
|
|
178
247
|
**Response example:**
|
|
179
248
|
|
|
180
249
|
```json
|
|
181
250
|
{
|
|
251
|
+
"blocked": false,
|
|
182
252
|
"status": "processed",
|
|
183
253
|
"monitoring_result": {
|
|
184
254
|
"is_toxic": false,
|
|
185
255
|
"type_of_violation": "safe",
|
|
186
256
|
"token_count": 21,
|
|
187
|
-
"
|
|
188
|
-
"token_usage_unbounded": false
|
|
257
|
+
"token_usage_severity": None
|
|
189
258
|
}
|
|
190
259
|
}
|
|
191
260
|
```
|
|
@@ -42,6 +42,16 @@ response = client.input(
|
|
|
42
42
|
application_id="your-application-id", # Obtained after registering the application in the UI
|
|
43
43
|
message="User prompt here",
|
|
44
44
|
)
|
|
45
|
+
|
|
46
|
+
# Optionally attach files (filename, bytes, mime_type)
|
|
47
|
+
files = [
|
|
48
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
49
|
+
]
|
|
50
|
+
response_with_files = client.input(
|
|
51
|
+
application_id="your-application-id",
|
|
52
|
+
message="User prompt with files",
|
|
53
|
+
files=files,
|
|
54
|
+
)
|
|
45
55
|
```
|
|
46
56
|
|
|
47
57
|
### Send an LLM response (output)
|
|
@@ -51,6 +61,16 @@ response = client.output(
|
|
|
51
61
|
application_id="your-application-id",
|
|
52
62
|
message="LLM response here",
|
|
53
63
|
)
|
|
64
|
+
|
|
65
|
+
# With files
|
|
66
|
+
files = [
|
|
67
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
68
|
+
]
|
|
69
|
+
response_with_files = client.output(
|
|
70
|
+
application_id="your-application-id",
|
|
71
|
+
message="LLM response with files",
|
|
72
|
+
files=files,
|
|
73
|
+
)
|
|
54
74
|
```
|
|
55
75
|
|
|
56
76
|
---
|
|
@@ -71,6 +91,16 @@ response = await client.input(
|
|
|
71
91
|
application_id="your-application-id",
|
|
72
92
|
message="User prompt here",
|
|
73
93
|
)
|
|
94
|
+
|
|
95
|
+
# With files (filename, bytes, mime_type)
|
|
96
|
+
files = [
|
|
97
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
98
|
+
]
|
|
99
|
+
response_with_files = await client.input(
|
|
100
|
+
application_id="your-application-id",
|
|
101
|
+
message="User prompt with files",
|
|
102
|
+
files=files,
|
|
103
|
+
)
|
|
74
104
|
```
|
|
75
105
|
|
|
76
106
|
### Send an LLM response (output)
|
|
@@ -80,6 +110,16 @@ response = await client.output(
|
|
|
80
110
|
application_id="your-application-id",
|
|
81
111
|
message="LLM response here",
|
|
82
112
|
)
|
|
113
|
+
|
|
114
|
+
# With files
|
|
115
|
+
files = [
|
|
116
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
117
|
+
]
|
|
118
|
+
response_with_files = await client.output(
|
|
119
|
+
application_id="your-application-id",
|
|
120
|
+
message="LLM response with files",
|
|
121
|
+
files=files,
|
|
122
|
+
)
|
|
83
123
|
```
|
|
84
124
|
|
|
85
125
|
---
|
|
@@ -97,13 +137,13 @@ response = client.input(
|
|
|
97
137
|
"agent-1-id": {"name": "Agent 1", "description": "Agent description"},
|
|
98
138
|
"agent-2-id": {"name": "Agent 2"},
|
|
99
139
|
"agent-3-id": {}
|
|
100
|
-
}
|
|
140
|
+
},
|
|
141
|
+
# If you want to send only to censor and avoid DB persistence on backend
|
|
142
|
+
"censor_only": True,
|
|
101
143
|
}
|
|
102
144
|
)
|
|
103
145
|
```
|
|
104
146
|
|
|
105
|
-
> **Note:** `session_id`, `user_id`, and all agent IDs must be valid UUIDs.
|
|
106
|
-
|
|
107
147
|
---
|
|
108
148
|
|
|
109
149
|
## API
|
|
@@ -112,10 +152,20 @@ response = client.input(
|
|
|
112
152
|
|
|
113
153
|
```python
|
|
114
154
|
# Sync
|
|
115
|
-
def input(
|
|
155
|
+
def input(
|
|
156
|
+
application_id: str,
|
|
157
|
+
message: str,
|
|
158
|
+
additional_parameters: dict | None = None,
|
|
159
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
160
|
+
) -> dict: ...
|
|
116
161
|
|
|
117
162
|
# Async
|
|
118
|
-
async def input(
|
|
163
|
+
async def input(
|
|
164
|
+
application_id: str,
|
|
165
|
+
message: str,
|
|
166
|
+
additional_parameters: dict | None = None,
|
|
167
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
168
|
+
) -> dict: ...
|
|
119
169
|
```
|
|
120
170
|
|
|
121
171
|
Sends a **user prompt** to Hivetrace.
|
|
@@ -123,18 +173,22 @@ Sends a **user prompt** to Hivetrace.
|
|
|
123
173
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
124
174
|
* `message` — The user prompt
|
|
125
175
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
176
|
+
- Supported special flags: `censor_only: bool` — when `True`, backend should not persist the message in DB and only pass it to the censor
|
|
177
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`; files are attached to the created analysis record
|
|
178
|
+
|
|
179
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
126
180
|
|
|
127
181
|
**Response example:**
|
|
128
182
|
|
|
129
183
|
```json
|
|
130
184
|
{
|
|
185
|
+
"blocked": false,
|
|
131
186
|
"status": "processed",
|
|
132
187
|
"monitoring_result": {
|
|
133
188
|
"is_toxic": false,
|
|
134
189
|
"type_of_violation": "benign",
|
|
135
190
|
"token_count": 9,
|
|
136
|
-
"
|
|
137
|
-
"token_usage_unbounded": false
|
|
191
|
+
"token_usage_severity": None
|
|
138
192
|
}
|
|
139
193
|
}
|
|
140
194
|
```
|
|
@@ -145,10 +199,20 @@ Sends a **user prompt** to Hivetrace.
|
|
|
145
199
|
|
|
146
200
|
```python
|
|
147
201
|
# Sync
|
|
148
|
-
def output(
|
|
202
|
+
def output(
|
|
203
|
+
application_id: str,
|
|
204
|
+
message: str,
|
|
205
|
+
additional_parameters: dict | None = None,
|
|
206
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
207
|
+
) -> dict: ...
|
|
149
208
|
|
|
150
209
|
# Async
|
|
151
|
-
async def output(
|
|
210
|
+
async def output(
|
|
211
|
+
application_id: str,
|
|
212
|
+
message: str,
|
|
213
|
+
additional_parameters: dict | None = None,
|
|
214
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
215
|
+
) -> dict: ...
|
|
152
216
|
```
|
|
153
217
|
|
|
154
218
|
Sends an **LLM response** to Hivetrace.
|
|
@@ -156,18 +220,23 @@ Sends an **LLM response** to Hivetrace.
|
|
|
156
220
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
157
221
|
* `message` — The LLM response
|
|
158
222
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
223
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`
|
|
224
|
+
|
|
225
|
+
> Files are uploaded after the main request completes and an analysis ID is available.
|
|
226
|
+
|
|
227
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
159
228
|
|
|
160
229
|
**Response example:**
|
|
161
230
|
|
|
162
231
|
```json
|
|
163
232
|
{
|
|
233
|
+
"blocked": false,
|
|
164
234
|
"status": "processed",
|
|
165
235
|
"monitoring_result": {
|
|
166
236
|
"is_toxic": false,
|
|
167
237
|
"type_of_violation": "safe",
|
|
168
238
|
"token_count": 21,
|
|
169
|
-
"
|
|
170
|
-
"token_usage_unbounded": false
|
|
239
|
+
"token_usage_severity": None
|
|
171
240
|
}
|
|
172
241
|
}
|
|
173
242
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import warnings
|
|
2
|
-
from typing import Any, Dict, Optional, Union
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
@@ -22,7 +22,6 @@ class AsyncHivetraceSDK(BaseHivetraceSDK):
|
|
|
22
22
|
def __init__(self, config: Optional[Dict[str, Any]] = None) -> None:
|
|
23
23
|
super().__init__(config)
|
|
24
24
|
self.session = httpx.AsyncClient()
|
|
25
|
-
# SDK асинхронный, задаем флаг для адаптеров
|
|
26
25
|
self.async_mode = True
|
|
27
26
|
|
|
28
27
|
async def __aenter__(self):
|
|
@@ -55,27 +54,90 @@ class AsyncHivetraceSDK(BaseHivetraceSDK):
|
|
|
55
54
|
except Exception as e:
|
|
56
55
|
return ErrorHandler.handle_unexpected_error(e)
|
|
57
56
|
|
|
57
|
+
async def _send_files(
|
|
58
|
+
self, endpoint: str, files: List[Tuple[str, bytes, str]]
|
|
59
|
+
) -> HivetraceResponse:
|
|
60
|
+
request_args = self._build_files_request_args(endpoint, files)
|
|
61
|
+
try:
|
|
62
|
+
response = await self.session.post(**request_args)
|
|
63
|
+
response.raise_for_status()
|
|
64
|
+
api_data = response.json()
|
|
65
|
+
return ResponseBuilder.build_response_from_api(api_data)
|
|
66
|
+
except httpx.HTTPStatusError as e:
|
|
67
|
+
return ErrorHandler.handle_http_error(e)
|
|
68
|
+
except httpx.ConnectError as e:
|
|
69
|
+
return ErrorHandler.handle_connection_error(e)
|
|
70
|
+
except httpx.TimeoutException as e:
|
|
71
|
+
return ErrorHandler.handle_timeout_error(e)
|
|
72
|
+
except httpx.RequestError as e:
|
|
73
|
+
return ErrorHandler.handle_request_error(e)
|
|
74
|
+
except ValueError as e:
|
|
75
|
+
return ErrorHandler.handle_json_decode_error(e)
|
|
76
|
+
except Exception as e:
|
|
77
|
+
return ErrorHandler.handle_unexpected_error(e)
|
|
78
|
+
|
|
79
|
+
async def _get_blocking_status(self, endpoint: str) -> Optional[bool]:
|
|
80
|
+
url = f"{self.hivetrace_url}/{endpoint.lstrip('/')}"
|
|
81
|
+
headers = {"Authorization": f"Bearer {self.hivetrace_access_token}"}
|
|
82
|
+
try:
|
|
83
|
+
response = await self.session.get(
|
|
84
|
+
url, headers=headers, timeout=self._DEFAULT_TIMEOUT
|
|
85
|
+
)
|
|
86
|
+
response.raise_for_status()
|
|
87
|
+
data = response.json()
|
|
88
|
+
return data.get("blocked")
|
|
89
|
+
except Exception:
|
|
90
|
+
return None
|
|
91
|
+
|
|
58
92
|
async def input(
|
|
59
93
|
self,
|
|
60
94
|
application_id: str,
|
|
61
95
|
message: str,
|
|
62
96
|
additional_parameters: Optional[Dict[str, Any]] = None,
|
|
97
|
+
files: Optional[List[Tuple[str, bytes, str]]] = None,
|
|
63
98
|
) -> HivetraceResponse:
|
|
64
99
|
payload = self._build_message_payload(
|
|
65
100
|
application_id, message, additional_parameters
|
|
66
101
|
)
|
|
67
|
-
|
|
102
|
+
process_response = await self._send_request("/process_request/", payload)
|
|
103
|
+
if files:
|
|
104
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
105
|
+
if analysis_id:
|
|
106
|
+
await self._send_files(
|
|
107
|
+
f"/user_prompt_analysis/{analysis_id}/attach_files", files
|
|
108
|
+
)
|
|
109
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
110
|
+
if analysis_id:
|
|
111
|
+
blocked = await self._get_blocking_status(
|
|
112
|
+
f"/user_prompt_analysis/{analysis_id}/check_blocking"
|
|
113
|
+
)
|
|
114
|
+
self._set_blocked(process_response, blocked)
|
|
115
|
+
return process_response
|
|
68
116
|
|
|
69
117
|
async def output(
|
|
70
118
|
self,
|
|
71
119
|
application_id: str,
|
|
72
120
|
message: str,
|
|
73
121
|
additional_parameters: Optional[Dict[str, Any]] = None,
|
|
122
|
+
files: Optional[List[Tuple[str, bytes, str]]] = None,
|
|
74
123
|
) -> HivetraceResponse:
|
|
75
124
|
payload = self._build_message_payload(
|
|
76
125
|
application_id, message, additional_parameters
|
|
77
126
|
)
|
|
78
|
-
|
|
127
|
+
process_response = await self._send_request("/process_response/", payload)
|
|
128
|
+
if files:
|
|
129
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
130
|
+
if analysis_id:
|
|
131
|
+
await self._send_files(
|
|
132
|
+
f"/llm_response_analysis/{analysis_id}/attach_files", files
|
|
133
|
+
)
|
|
134
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
135
|
+
if analysis_id:
|
|
136
|
+
blocked = await self._get_blocking_status(
|
|
137
|
+
f"/llm_response_analysis/{analysis_id}/check_blocking"
|
|
138
|
+
)
|
|
139
|
+
self._set_blocked(process_response, blocked)
|
|
140
|
+
return process_response
|
|
79
141
|
|
|
80
142
|
async def function_call(
|
|
81
143
|
self,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import uuid
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from typing import Any, Dict, Optional, Union
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
7
|
from pydantic import ValidationError
|
|
@@ -94,6 +94,58 @@ class BaseHivetraceSDK(ABC):
|
|
|
94
94
|
"timeout": self._DEFAULT_TIMEOUT,
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
def _build_files_request_args(
|
|
98
|
+
self,
|
|
99
|
+
endpoint: str,
|
|
100
|
+
files: List[Tuple[str, bytes, str]],
|
|
101
|
+
files_field_name: str = "attached_files",
|
|
102
|
+
) -> Dict[str, Any]:
|
|
103
|
+
"""Builds request args for multipart file upload."""
|
|
104
|
+
url = f"{self.hivetrace_url}/{endpoint.lstrip('/')}"
|
|
105
|
+
headers = {"Authorization": f"Bearer {self.hivetrace_access_token}"}
|
|
106
|
+
return {
|
|
107
|
+
"url": url,
|
|
108
|
+
"files": self._prepare_files_param(files, files_field_name),
|
|
109
|
+
"headers": headers,
|
|
110
|
+
"timeout": self._DEFAULT_TIMEOUT,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _prepare_files_param(
|
|
115
|
+
files: List[Tuple[str, bytes, str]],
|
|
116
|
+
files_field_name: str = "attached_files",
|
|
117
|
+
) -> List[Tuple[str, Tuple[str, bytes, str]]]:
|
|
118
|
+
files_param: List[Tuple[str, Tuple[str, bytes, str]]] = []
|
|
119
|
+
for file_tuple in files:
|
|
120
|
+
files_param.append((files_field_name, file_tuple))
|
|
121
|
+
return files_param
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _extract_analysis_id(response: Any) -> Optional[str]:
|
|
125
|
+
"""Extracts analysis id from API response if present."""
|
|
126
|
+
try:
|
|
127
|
+
if isinstance(response, dict):
|
|
128
|
+
monitoring_result = response.get("monitoring_result", {})
|
|
129
|
+
analysis_id = monitoring_result.get("id")
|
|
130
|
+
return str(analysis_id) if analysis_id is not None else None
|
|
131
|
+
except Exception:
|
|
132
|
+
return None
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def _set_blocked(response: Any, blocked: Optional[bool]) -> Any:
|
|
137
|
+
"""Sets 'blocked' flag on response when possible."""
|
|
138
|
+
try:
|
|
139
|
+
if isinstance(response, dict):
|
|
140
|
+
response["blocked"] = blocked
|
|
141
|
+
return response
|
|
142
|
+
if hasattr(response, "blocked"):
|
|
143
|
+
setattr(response, "blocked", blocked)
|
|
144
|
+
return response
|
|
145
|
+
except Exception:
|
|
146
|
+
return response
|
|
147
|
+
return response
|
|
148
|
+
|
|
97
149
|
def _handle_http_error(self, error: httpx.HTTPStatusError) -> HivetraceResponse:
|
|
98
150
|
return ErrorHandler.handle_http_error(error)
|
|
99
151
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import weakref
|
|
2
|
-
from typing import Any, Dict, Optional, Union
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
@@ -67,27 +67,92 @@ class SyncHivetraceSDK(BaseHivetraceSDK):
|
|
|
67
67
|
except Exception as e:
|
|
68
68
|
return ErrorHandler.handle_unexpected_error(e)
|
|
69
69
|
|
|
70
|
+
def _send_files(
|
|
71
|
+
self, endpoint: str, files: List[Tuple[str, bytes, str]]
|
|
72
|
+
) -> HivetraceResponse:
|
|
73
|
+
request_args = self._build_files_request_args(endpoint, files)
|
|
74
|
+
try:
|
|
75
|
+
response = self.session.post(**request_args)
|
|
76
|
+
response.raise_for_status()
|
|
77
|
+
|
|
78
|
+
api_data = response.json()
|
|
79
|
+
return ResponseBuilder.build_response_from_api(api_data)
|
|
80
|
+
|
|
81
|
+
except httpx.HTTPStatusError as e:
|
|
82
|
+
return ErrorHandler.handle_http_error(e)
|
|
83
|
+
except httpx.ConnectError as e:
|
|
84
|
+
return ErrorHandler.handle_connection_error(e)
|
|
85
|
+
except httpx.TimeoutException as e:
|
|
86
|
+
return ErrorHandler.handle_timeout_error(e)
|
|
87
|
+
except httpx.RequestError as e:
|
|
88
|
+
return ErrorHandler.handle_request_error(e)
|
|
89
|
+
except ValueError as e:
|
|
90
|
+
return ErrorHandler.handle_json_decode_error(e)
|
|
91
|
+
except Exception as e:
|
|
92
|
+
return ErrorHandler.handle_unexpected_error(e)
|
|
93
|
+
|
|
94
|
+
def _get_blocking_status(self, endpoint: str) -> Optional[bool]:
|
|
95
|
+
url = f"{self.hivetrace_url}/{endpoint.lstrip('/')}"
|
|
96
|
+
headers = {"Authorization": f"Bearer {self.hivetrace_access_token}"}
|
|
97
|
+
try:
|
|
98
|
+
response = self.session.get(
|
|
99
|
+
url, headers=headers, timeout=self._DEFAULT_TIMEOUT
|
|
100
|
+
)
|
|
101
|
+
response.raise_for_status()
|
|
102
|
+
data = response.json()
|
|
103
|
+
return data.get("blocked")
|
|
104
|
+
except Exception:
|
|
105
|
+
return None
|
|
106
|
+
|
|
70
107
|
def input(
|
|
71
108
|
self,
|
|
72
109
|
application_id: str,
|
|
73
110
|
message: str,
|
|
74
111
|
additional_parameters: Optional[Dict[str, Any]] = None,
|
|
112
|
+
files: Optional[List[Tuple[str, bytes, str]]] = None,
|
|
75
113
|
) -> HivetraceResponse:
|
|
76
114
|
payload = self._build_message_payload(
|
|
77
115
|
application_id, message, additional_parameters
|
|
78
116
|
)
|
|
79
|
-
|
|
117
|
+
process_response = self._send_request("/process_request/", payload)
|
|
118
|
+
if files:
|
|
119
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
120
|
+
if analysis_id:
|
|
121
|
+
self._send_files(
|
|
122
|
+
f"/user_prompt_analysis/{analysis_id}/attach_files", files
|
|
123
|
+
)
|
|
124
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
125
|
+
if analysis_id:
|
|
126
|
+
blocked = self._get_blocking_status(
|
|
127
|
+
f"/user_prompt_analysis/{analysis_id}/check_blocking"
|
|
128
|
+
)
|
|
129
|
+
self._set_blocked(process_response, blocked)
|
|
130
|
+
return process_response
|
|
80
131
|
|
|
81
132
|
def output(
|
|
82
133
|
self,
|
|
83
134
|
application_id: str,
|
|
84
135
|
message: str,
|
|
85
136
|
additional_parameters: Optional[Dict[str, Any]] = None,
|
|
137
|
+
files: Optional[List[Tuple[str, bytes, str]]] = None,
|
|
86
138
|
) -> HivetraceResponse:
|
|
87
139
|
payload = self._build_message_payload(
|
|
88
140
|
application_id, message, additional_parameters
|
|
89
141
|
)
|
|
90
|
-
|
|
142
|
+
process_response = self._send_request("/process_response/", payload)
|
|
143
|
+
if files:
|
|
144
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
145
|
+
if analysis_id:
|
|
146
|
+
self._send_files(
|
|
147
|
+
f"/llm_response_analysis/{analysis_id}/attach_files", files
|
|
148
|
+
)
|
|
149
|
+
analysis_id = self._extract_analysis_id(process_response)
|
|
150
|
+
if analysis_id:
|
|
151
|
+
blocked = self._get_blocking_status(
|
|
152
|
+
f"/llm_response_analysis/{analysis_id}/check_blocking"
|
|
153
|
+
)
|
|
154
|
+
self._set_blocked(process_response, blocked)
|
|
155
|
+
return process_response
|
|
91
156
|
|
|
92
157
|
def function_call(
|
|
93
158
|
self,
|
|
@@ -15,10 +15,10 @@ class BaseRequest(BaseModel):
|
|
|
15
15
|
class MessageRequest(BaseRequest):
|
|
16
16
|
"""Base model for requests with message and additional parameters."""
|
|
17
17
|
|
|
18
|
-
application_id: str = Field(..., description="ID
|
|
19
|
-
message: str = Field(..., min_length=1, description="
|
|
18
|
+
application_id: str = Field(..., description="Application ID (UUID)")
|
|
19
|
+
message: str = Field(..., min_length=1, description="Message text")
|
|
20
20
|
additional_parameters: Optional[Dict[str, Any]] = Field(
|
|
21
|
-
None, description="
|
|
21
|
+
None, description="Additional parameters"
|
|
22
22
|
)
|
|
23
23
|
|
|
24
24
|
@validator("application_id")
|
|
@@ -24,6 +24,10 @@ class ProcessResponse(SuccessResponse):
|
|
|
24
24
|
|
|
25
25
|
message_id: Optional[str] = Field(None, description="ID of processed message")
|
|
26
26
|
trace_id: Optional[str] = Field(None, description="Trace ID")
|
|
27
|
+
blocked: Optional[bool] = Field(
|
|
28
|
+
None,
|
|
29
|
+
description="Role restriction flag. True if message/response is blocked by policy.",
|
|
30
|
+
)
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
class ErrorResponse(BaseResponse):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hivetrace
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.10
|
|
4
4
|
Summary: Hivetrace SDK for monitoring LLM applications
|
|
5
5
|
Home-page: http://hivetrace.ai
|
|
6
6
|
Author: Raft
|
|
@@ -60,6 +60,16 @@ response = client.input(
|
|
|
60
60
|
application_id="your-application-id", # Obtained after registering the application in the UI
|
|
61
61
|
message="User prompt here",
|
|
62
62
|
)
|
|
63
|
+
|
|
64
|
+
# Optionally attach files (filename, bytes, mime_type)
|
|
65
|
+
files = [
|
|
66
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
67
|
+
]
|
|
68
|
+
response_with_files = client.input(
|
|
69
|
+
application_id="your-application-id",
|
|
70
|
+
message="User prompt with files",
|
|
71
|
+
files=files,
|
|
72
|
+
)
|
|
63
73
|
```
|
|
64
74
|
|
|
65
75
|
### Send an LLM response (output)
|
|
@@ -69,6 +79,16 @@ response = client.output(
|
|
|
69
79
|
application_id="your-application-id",
|
|
70
80
|
message="LLM response here",
|
|
71
81
|
)
|
|
82
|
+
|
|
83
|
+
# With files
|
|
84
|
+
files = [
|
|
85
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
86
|
+
]
|
|
87
|
+
response_with_files = client.output(
|
|
88
|
+
application_id="your-application-id",
|
|
89
|
+
message="LLM response with files",
|
|
90
|
+
files=files,
|
|
91
|
+
)
|
|
72
92
|
```
|
|
73
93
|
|
|
74
94
|
---
|
|
@@ -89,6 +109,16 @@ response = await client.input(
|
|
|
89
109
|
application_id="your-application-id",
|
|
90
110
|
message="User prompt here",
|
|
91
111
|
)
|
|
112
|
+
|
|
113
|
+
# With files (filename, bytes, mime_type)
|
|
114
|
+
files = [
|
|
115
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
116
|
+
]
|
|
117
|
+
response_with_files = await client.input(
|
|
118
|
+
application_id="your-application-id",
|
|
119
|
+
message="User prompt with files",
|
|
120
|
+
files=files,
|
|
121
|
+
)
|
|
92
122
|
```
|
|
93
123
|
|
|
94
124
|
### Send an LLM response (output)
|
|
@@ -98,6 +128,16 @@ response = await client.output(
|
|
|
98
128
|
application_id="your-application-id",
|
|
99
129
|
message="LLM response here",
|
|
100
130
|
)
|
|
131
|
+
|
|
132
|
+
# With files
|
|
133
|
+
files = [
|
|
134
|
+
("doc1.txt", open("doc1.txt", "rb"), "text/plain"),
|
|
135
|
+
]
|
|
136
|
+
response_with_files = await client.output(
|
|
137
|
+
application_id="your-application-id",
|
|
138
|
+
message="LLM response with files",
|
|
139
|
+
files=files,
|
|
140
|
+
)
|
|
101
141
|
```
|
|
102
142
|
|
|
103
143
|
---
|
|
@@ -115,13 +155,13 @@ response = client.input(
|
|
|
115
155
|
"agent-1-id": {"name": "Agent 1", "description": "Agent description"},
|
|
116
156
|
"agent-2-id": {"name": "Agent 2"},
|
|
117
157
|
"agent-3-id": {}
|
|
118
|
-
}
|
|
158
|
+
},
|
|
159
|
+
# If you want to send only to censor and avoid DB persistence on backend
|
|
160
|
+
"censor_only": True,
|
|
119
161
|
}
|
|
120
162
|
)
|
|
121
163
|
```
|
|
122
164
|
|
|
123
|
-
> **Note:** `session_id`, `user_id`, and all agent IDs must be valid UUIDs.
|
|
124
|
-
|
|
125
165
|
---
|
|
126
166
|
|
|
127
167
|
## API
|
|
@@ -130,10 +170,20 @@ response = client.input(
|
|
|
130
170
|
|
|
131
171
|
```python
|
|
132
172
|
# Sync
|
|
133
|
-
def input(
|
|
173
|
+
def input(
|
|
174
|
+
application_id: str,
|
|
175
|
+
message: str,
|
|
176
|
+
additional_parameters: dict | None = None,
|
|
177
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
178
|
+
) -> dict: ...
|
|
134
179
|
|
|
135
180
|
# Async
|
|
136
|
-
async def input(
|
|
181
|
+
async def input(
|
|
182
|
+
application_id: str,
|
|
183
|
+
message: str,
|
|
184
|
+
additional_parameters: dict | None = None,
|
|
185
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
186
|
+
) -> dict: ...
|
|
137
187
|
```
|
|
138
188
|
|
|
139
189
|
Sends a **user prompt** to Hivetrace.
|
|
@@ -141,18 +191,22 @@ Sends a **user prompt** to Hivetrace.
|
|
|
141
191
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
142
192
|
* `message` — The user prompt
|
|
143
193
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
194
|
+
- Supported special flags: `censor_only: bool` — when `True`, backend should not persist the message in DB and only pass it to the censor
|
|
195
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`; files are attached to the created analysis record
|
|
196
|
+
|
|
197
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
144
198
|
|
|
145
199
|
**Response example:**
|
|
146
200
|
|
|
147
201
|
```json
|
|
148
202
|
{
|
|
203
|
+
"blocked": false,
|
|
149
204
|
"status": "processed",
|
|
150
205
|
"monitoring_result": {
|
|
151
206
|
"is_toxic": false,
|
|
152
207
|
"type_of_violation": "benign",
|
|
153
208
|
"token_count": 9,
|
|
154
|
-
"
|
|
155
|
-
"token_usage_unbounded": false
|
|
209
|
+
"token_usage_severity": None
|
|
156
210
|
}
|
|
157
211
|
}
|
|
158
212
|
```
|
|
@@ -163,10 +217,20 @@ Sends a **user prompt** to Hivetrace.
|
|
|
163
217
|
|
|
164
218
|
```python
|
|
165
219
|
# Sync
|
|
166
|
-
def output(
|
|
220
|
+
def output(
|
|
221
|
+
application_id: str,
|
|
222
|
+
message: str,
|
|
223
|
+
additional_parameters: dict | None = None,
|
|
224
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
225
|
+
) -> dict: ...
|
|
167
226
|
|
|
168
227
|
# Async
|
|
169
|
-
async def output(
|
|
228
|
+
async def output(
|
|
229
|
+
application_id: str,
|
|
230
|
+
message: str,
|
|
231
|
+
additional_parameters: dict | None = None,
|
|
232
|
+
files: list[tuple[str, bytes, str]] | None = None,
|
|
233
|
+
) -> dict: ...
|
|
170
234
|
```
|
|
171
235
|
|
|
172
236
|
Sends an **LLM response** to Hivetrace.
|
|
@@ -174,18 +238,23 @@ Sends an **LLM response** to Hivetrace.
|
|
|
174
238
|
* `application_id` — Application identifier (must be a valid UUID, created in the UI)
|
|
175
239
|
* `message` — The LLM response
|
|
176
240
|
* `additional_parameters` — Optional dictionary with extra context (session, user, agents, etc.)
|
|
241
|
+
* `files` — Optional list of tuples `(filename: str, content: bytes, mime_type: str)`
|
|
242
|
+
|
|
243
|
+
> Files are uploaded after the main request completes and an analysis ID is available.
|
|
244
|
+
|
|
245
|
+
Response contains a `blocked` flag that indicates role restrictions.
|
|
177
246
|
|
|
178
247
|
**Response example:**
|
|
179
248
|
|
|
180
249
|
```json
|
|
181
250
|
{
|
|
251
|
+
"blocked": false,
|
|
182
252
|
"status": "processed",
|
|
183
253
|
"monitoring_result": {
|
|
184
254
|
"is_toxic": false,
|
|
185
255
|
"type_of_violation": "safe",
|
|
186
256
|
"token_count": 21,
|
|
187
|
-
"
|
|
188
|
-
"token_usage_unbounded": false
|
|
257
|
+
"token_usage_severity": None
|
|
189
258
|
}
|
|
190
259
|
}
|
|
191
260
|
```
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
httpx>=0.28.1
|
|
2
|
+
pydantic>=2.11.7
|
|
2
3
|
python-dotenv>=1.0.1
|
|
3
4
|
|
|
4
5
|
[all]
|
|
@@ -9,10 +10,12 @@ langchain-openai==0.2.5
|
|
|
9
10
|
langchain==0.3.19
|
|
10
11
|
langchain_experimental==0.3.4
|
|
11
12
|
openai-agents>=0.1.0
|
|
13
|
+
pydantic>=2.11.7
|
|
12
14
|
python-dotenv>=1.0.1
|
|
13
15
|
|
|
14
16
|
[base]
|
|
15
17
|
httpx>=0.28.1
|
|
18
|
+
pydantic>=2.11.7
|
|
16
19
|
python-dotenv>=1.0.1
|
|
17
20
|
|
|
18
21
|
[crewai]
|
|
@@ -9,6 +9,7 @@ def readme():
|
|
|
9
9
|
base_requires = [
|
|
10
10
|
"httpx>=0.28.1",
|
|
11
11
|
"python-dotenv>=1.0.1",
|
|
12
|
+
"pydantic>=2.11.7",
|
|
12
13
|
]
|
|
13
14
|
|
|
14
15
|
langchain_requires = [
|
|
@@ -28,7 +29,7 @@ openai_agents_requires = [
|
|
|
28
29
|
|
|
29
30
|
setup(
|
|
30
31
|
name="hivetrace",
|
|
31
|
-
version="1.3.
|
|
32
|
+
version="1.3.10",
|
|
32
33
|
author="Raft",
|
|
33
34
|
author_email="sales@raftds.com",
|
|
34
35
|
description="Hivetrace SDK for monitoring LLM applications",
|
|
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
|
|
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
|