trellar 0.3.0__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.
- trellar-0.3.0/LICENSE +21 -0
- trellar-0.3.0/PKG-INFO +211 -0
- trellar-0.3.0/README.md +183 -0
- trellar-0.3.0/pyproject.toml +47 -0
- trellar-0.3.0/setup.cfg +4 -0
- trellar-0.3.0/tests/test_agent_guard.py +105 -0
- trellar-0.3.0/tests/test_agent_loop.py +149 -0
- trellar-0.3.0/tests/test_langchain_callback.py +133 -0
- trellar-0.3.0/trellar/__init__.py +15 -0
- trellar-0.3.0/trellar/_context.py +11 -0
- trellar-0.3.0/trellar/agent_loop.py +174 -0
- trellar-0.3.0/trellar/callbacks/__init__.py +0 -0
- trellar-0.3.0/trellar/callbacks/langchain_callback.py +689 -0
- trellar-0.3.0/trellar/settings.py +10 -0
- trellar-0.3.0/trellar.egg-info/PKG-INFO +211 -0
- trellar-0.3.0/trellar.egg-info/SOURCES.txt +17 -0
- trellar-0.3.0/trellar.egg-info/dependency_links.txt +1 -0
- trellar-0.3.0/trellar.egg-info/requires.txt +8 -0
- trellar-0.3.0/trellar.egg-info/top_level.txt +1 -0
trellar-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Tomer Ben Harush
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trellar-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trellar
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Client library for the Trellar confidence evaluation API
|
|
5
|
+
Author: Tomer Ben Harush
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/benarush/AITL
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/benarush/AITL/issues
|
|
9
|
+
Keywords: agent,llm,opentelemetry,confidence,ai
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: requests>=2.28
|
|
22
|
+
Requires-Dist: opentelemetry-sdk>=1.20
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
25
|
+
Provides-Extra: langchain
|
|
26
|
+
Requires-Dist: langchain-core>=0.1; extra == "langchain"
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# trellar
|
|
30
|
+
|
|
31
|
+
[](https://pypi.org/project/trellar/)
|
|
32
|
+
[](https://pypi.org/project/trellar/)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
[](https://github.com/benarush/AITL/actions/workflows/ci.yml)
|
|
35
|
+
|
|
36
|
+
A lightweight Python client for the **Trellar** confidence evaluation API. Attach a callback to your LangChain / LangGraph run, then call `evaluate_confidence()` when you want a score. Context, trace ID, and agent name are picked up automatically — no manual wiring.
|
|
37
|
+
|
|
38
|
+
This library cannot be used without an API key from [trellar.io](https://trellar.io).
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Create an account and API key
|
|
43
|
+
|
|
44
|
+
[trellar.io](https://trellar.io) is the only place that issues API keys for this library. Create an account there, then generate an API key from the dashboard. Without that key, `evaluate_confidence()` cannot authenticate and the client will not work.
|
|
45
|
+
|
|
46
|
+
Then pass the key into the SDK (see [Environment Variables](#environment-variables)):
|
|
47
|
+
|
|
48
|
+
- `evaluate_confidence(api_key="...")`, or
|
|
49
|
+
- `TRELLAR_API_KEY` in the environment
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install "trellar[langchain]"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The `langchain` extra is required because agent runs are captured via a LangChain callback handler (`get_agent_guard`). Requires Python 3.9+.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from trellar import get_agent_guard, evaluate_confidence
|
|
67
|
+
|
|
68
|
+
# agent_name must be a stable, unique name for this agent graph — the
|
|
69
|
+
# backend uses it to track the graph's network profile across runs.
|
|
70
|
+
guard = get_agent_guard("research-agent")
|
|
71
|
+
|
|
72
|
+
graph.invoke(inputs, config={"callbacks": [guard]})
|
|
73
|
+
|
|
74
|
+
# context, trace_id, and agent_name are picked up from the guard
|
|
75
|
+
result = evaluate_confidence()
|
|
76
|
+
print(result.score) # int, 1-10
|
|
77
|
+
print(result.explanation) # str, human-readable reasoning
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Where to call `evaluate_confidence`
|
|
83
|
+
|
|
84
|
+
Call it from a graph node (or after `invoke()`), at the point in the run you want scored. The payload is the events captured **so far** — later nodes are not included.
|
|
85
|
+
|
|
86
|
+
There are two ways to use the result:
|
|
87
|
+
|
|
88
|
+
### 1. Gate — validate before the graph continues
|
|
89
|
+
|
|
90
|
+
Put the call on an edge you do not want the graph to cross until Trellar has scored the run. Use `result.score` / `result.explanation` to decide whether to proceed or stop.
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
def confidence_gate(state):
|
|
94
|
+
result = evaluate_confidence()
|
|
95
|
+
if result.score < 7:
|
|
96
|
+
return {**state, "halt": True, "reason": result.explanation}
|
|
97
|
+
return {**state, "halt": False}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Wire that node in front of the next step, and only continue when the score is acceptable.
|
|
101
|
+
|
|
102
|
+
### 2. Observe — send a validation, do not restrict the graph
|
|
103
|
+
|
|
104
|
+
Put the call anywhere you want a score recorded (a node, or after `invoke()`). Store or log `result` if you want it; do not branch on it. The graph continues either way.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
def report_confidence(state):
|
|
108
|
+
result = evaluate_confidence()
|
|
109
|
+
return {**state, "confidence_score": result.score, "confidence_explanation": result.explanation}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Environment Variables
|
|
115
|
+
|
|
116
|
+
The SDK always talks to the managed Trellar backend at `https://api.trellar.io` — this is fixed and cannot be overridden via an environment variable or function argument.
|
|
117
|
+
|
|
118
|
+
The API key itself is created only at [trellar.io](https://trellar.io). Once you have it, you can pass it to `evaluate_confidence(api_key=...)` or set it as an environment variable so you do not pass it on every call:
|
|
119
|
+
|
|
120
|
+
| Variable | Description | Default |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `TRELLAR_API_KEY` | Bearer token for authentication | *(required)* |
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
export TRELLAR_API_KEY=your-api-key
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
result = evaluate_confidence() # api_key read from the env var
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## API Reference
|
|
135
|
+
|
|
136
|
+
### `get_agent_guard`
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
get_agent_guard(
|
|
140
|
+
agent_name: str,
|
|
141
|
+
observability_mode: ObservabilityMode = ObservabilityMode.NONE,
|
|
142
|
+
) -> BaseCallbackHandler
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| Parameter | Type | Description |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `agent_name` | `str` | Stable, unique name identifying this agent graph (e.g. `"research-agent"`) |
|
|
148
|
+
| `observability_mode` | `ObservabilityMode` | Controls whether `evaluate_confidence()` is auto-triggered when the graph run finishes. Default `ObservabilityMode.NONE` (no auto-trigger). |
|
|
149
|
+
|
|
150
|
+
Returns a LangChain callback handler bound to `agent_name`. Pass it to `graph.invoke(..., config={"callbacks": [guard]})`.
|
|
151
|
+
|
|
152
|
+
**Raises:**
|
|
153
|
+
- `ValueError` — if `agent_name` is empty or blank
|
|
154
|
+
|
|
155
|
+
#### `ObservabilityMode`
|
|
156
|
+
|
|
157
|
+
Controls whether the guard automatically calls `evaluate_confidence()` for you when the graph run finishes (the root `graph.invoke()` call completes), so you don't have to add a manual call yourself.
|
|
158
|
+
|
|
159
|
+
| Value | Behavior |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `ObservabilityMode.NONE` | Never auto-call. Default; identical to not passing `observability_mode` at all. |
|
|
162
|
+
| `ObservabilityMode.ALWAYS` | Always call `evaluate_confidence()` when the run finishes. |
|
|
163
|
+
| `ObservabilityMode.IF_NOT_EVALUATED` | Call `evaluate_confidence()` when the run finishes only if it was not already successfully called earlier in the run (e.g. from a gate node). |
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from trellar import get_agent_guard, ObservabilityMode
|
|
167
|
+
|
|
168
|
+
guard = get_agent_guard("research-agent", ObservabilityMode.IF_NOT_EVALUATED)
|
|
169
|
+
graph.invoke(inputs, config={"callbacks": [guard]})
|
|
170
|
+
# evaluate_confidence() has already run automatically if no node called it.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Auto-triggered calls never raise: any error (missing API key, HTTP error, `NetworkHaltedError`, etc.) is caught and logged instead of propagating out of `graph.invoke()`. A manual call to `evaluate_confidence()` still raises normally.
|
|
174
|
+
|
|
175
|
+
Requests triggered this way are marked in the payload sent to the backend with `observability_call: true` (`false` for a normal, manually-invoked call), so the backend can distinguish automatic observability calls from explicit ones.
|
|
176
|
+
|
|
177
|
+
### `evaluate_confidence`
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
evaluate_confidence(
|
|
181
|
+
*,
|
|
182
|
+
api_key: str | None = None,
|
|
183
|
+
timeout: float = 30.0,
|
|
184
|
+
) -> AgentLoopResult
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Parameter | Type | Description |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| `api_key` | `str \| None` | Bearer token. Falls back to `TRELLAR_API_KEY` |
|
|
190
|
+
| `timeout` | `float` | HTTP request timeout in seconds (default `30.0`) |
|
|
191
|
+
|
|
192
|
+
`context`, `trace_id`, and `agent_name` are resolved automatically from the active guard created by `get_agent_guard` — there is no way to pass them manually. Requests always go to `https://api.trellar.io`; callers cannot redirect them.
|
|
193
|
+
|
|
194
|
+
**Raises:**
|
|
195
|
+
- `ValueError` — if no active guard is found, its `trace_id` cannot be resolved, or `api_key` is missing
|
|
196
|
+
- `requests.HTTPError` — on non-2xx HTTP responses
|
|
197
|
+
|
|
198
|
+
### `AgentLoopResult`
|
|
199
|
+
|
|
200
|
+
A frozen dataclass with two fields:
|
|
201
|
+
|
|
202
|
+
| Field | Type | Description |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `score` | `int` | Confidence score from 1 (low) to 10 (high) |
|
|
205
|
+
| `explanation` | `str` | Human-readable explanation of the score |
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT — see [LICENSE](LICENSE) for details.
|
trellar-0.3.0/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# trellar
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/trellar/)
|
|
4
|
+
[](https://pypi.org/project/trellar/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://github.com/benarush/AITL/actions/workflows/ci.yml)
|
|
7
|
+
|
|
8
|
+
A lightweight Python client for the **Trellar** confidence evaluation API. Attach a callback to your LangChain / LangGraph run, then call `evaluate_confidence()` when you want a score. Context, trace ID, and agent name are picked up automatically — no manual wiring.
|
|
9
|
+
|
|
10
|
+
This library cannot be used without an API key from [trellar.io](https://trellar.io).
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Create an account and API key
|
|
15
|
+
|
|
16
|
+
[trellar.io](https://trellar.io) is the only place that issues API keys for this library. Create an account there, then generate an API key from the dashboard. Without that key, `evaluate_confidence()` cannot authenticate and the client will not work.
|
|
17
|
+
|
|
18
|
+
Then pass the key into the SDK (see [Environment Variables](#environment-variables)):
|
|
19
|
+
|
|
20
|
+
- `evaluate_confidence(api_key="...")`, or
|
|
21
|
+
- `TRELLAR_API_KEY` in the environment
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install "trellar[langchain]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `langchain` extra is required because agent runs are captured via a LangChain callback handler (`get_agent_guard`). Requires Python 3.9+.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from trellar import get_agent_guard, evaluate_confidence
|
|
39
|
+
|
|
40
|
+
# agent_name must be a stable, unique name for this agent graph — the
|
|
41
|
+
# backend uses it to track the graph's network profile across runs.
|
|
42
|
+
guard = get_agent_guard("research-agent")
|
|
43
|
+
|
|
44
|
+
graph.invoke(inputs, config={"callbacks": [guard]})
|
|
45
|
+
|
|
46
|
+
# context, trace_id, and agent_name are picked up from the guard
|
|
47
|
+
result = evaluate_confidence()
|
|
48
|
+
print(result.score) # int, 1-10
|
|
49
|
+
print(result.explanation) # str, human-readable reasoning
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Where to call `evaluate_confidence`
|
|
55
|
+
|
|
56
|
+
Call it from a graph node (or after `invoke()`), at the point in the run you want scored. The payload is the events captured **so far** — later nodes are not included.
|
|
57
|
+
|
|
58
|
+
There are two ways to use the result:
|
|
59
|
+
|
|
60
|
+
### 1. Gate — validate before the graph continues
|
|
61
|
+
|
|
62
|
+
Put the call on an edge you do not want the graph to cross until Trellar has scored the run. Use `result.score` / `result.explanation` to decide whether to proceed or stop.
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
def confidence_gate(state):
|
|
66
|
+
result = evaluate_confidence()
|
|
67
|
+
if result.score < 7:
|
|
68
|
+
return {**state, "halt": True, "reason": result.explanation}
|
|
69
|
+
return {**state, "halt": False}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Wire that node in front of the next step, and only continue when the score is acceptable.
|
|
73
|
+
|
|
74
|
+
### 2. Observe — send a validation, do not restrict the graph
|
|
75
|
+
|
|
76
|
+
Put the call anywhere you want a score recorded (a node, or after `invoke()`). Store or log `result` if you want it; do not branch on it. The graph continues either way.
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
def report_confidence(state):
|
|
80
|
+
result = evaluate_confidence()
|
|
81
|
+
return {**state, "confidence_score": result.score, "confidence_explanation": result.explanation}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Environment Variables
|
|
87
|
+
|
|
88
|
+
The SDK always talks to the managed Trellar backend at `https://api.trellar.io` — this is fixed and cannot be overridden via an environment variable or function argument.
|
|
89
|
+
|
|
90
|
+
The API key itself is created only at [trellar.io](https://trellar.io). Once you have it, you can pass it to `evaluate_confidence(api_key=...)` or set it as an environment variable so you do not pass it on every call:
|
|
91
|
+
|
|
92
|
+
| Variable | Description | Default |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `TRELLAR_API_KEY` | Bearer token for authentication | *(required)* |
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
export TRELLAR_API_KEY=your-api-key
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
result = evaluate_confidence() # api_key read from the env var
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## API Reference
|
|
107
|
+
|
|
108
|
+
### `get_agent_guard`
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
get_agent_guard(
|
|
112
|
+
agent_name: str,
|
|
113
|
+
observability_mode: ObservabilityMode = ObservabilityMode.NONE,
|
|
114
|
+
) -> BaseCallbackHandler
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Description |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `agent_name` | `str` | Stable, unique name identifying this agent graph (e.g. `"research-agent"`) |
|
|
120
|
+
| `observability_mode` | `ObservabilityMode` | Controls whether `evaluate_confidence()` is auto-triggered when the graph run finishes. Default `ObservabilityMode.NONE` (no auto-trigger). |
|
|
121
|
+
|
|
122
|
+
Returns a LangChain callback handler bound to `agent_name`. Pass it to `graph.invoke(..., config={"callbacks": [guard]})`.
|
|
123
|
+
|
|
124
|
+
**Raises:**
|
|
125
|
+
- `ValueError` — if `agent_name` is empty or blank
|
|
126
|
+
|
|
127
|
+
#### `ObservabilityMode`
|
|
128
|
+
|
|
129
|
+
Controls whether the guard automatically calls `evaluate_confidence()` for you when the graph run finishes (the root `graph.invoke()` call completes), so you don't have to add a manual call yourself.
|
|
130
|
+
|
|
131
|
+
| Value | Behavior |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `ObservabilityMode.NONE` | Never auto-call. Default; identical to not passing `observability_mode` at all. |
|
|
134
|
+
| `ObservabilityMode.ALWAYS` | Always call `evaluate_confidence()` when the run finishes. |
|
|
135
|
+
| `ObservabilityMode.IF_NOT_EVALUATED` | Call `evaluate_confidence()` when the run finishes only if it was not already successfully called earlier in the run (e.g. from a gate node). |
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from trellar import get_agent_guard, ObservabilityMode
|
|
139
|
+
|
|
140
|
+
guard = get_agent_guard("research-agent", ObservabilityMode.IF_NOT_EVALUATED)
|
|
141
|
+
graph.invoke(inputs, config={"callbacks": [guard]})
|
|
142
|
+
# evaluate_confidence() has already run automatically if no node called it.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Auto-triggered calls never raise: any error (missing API key, HTTP error, `NetworkHaltedError`, etc.) is caught and logged instead of propagating out of `graph.invoke()`. A manual call to `evaluate_confidence()` still raises normally.
|
|
146
|
+
|
|
147
|
+
Requests triggered this way are marked in the payload sent to the backend with `observability_call: true` (`false` for a normal, manually-invoked call), so the backend can distinguish automatic observability calls from explicit ones.
|
|
148
|
+
|
|
149
|
+
### `evaluate_confidence`
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
evaluate_confidence(
|
|
153
|
+
*,
|
|
154
|
+
api_key: str | None = None,
|
|
155
|
+
timeout: float = 30.0,
|
|
156
|
+
) -> AgentLoopResult
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
| Parameter | Type | Description |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| `api_key` | `str \| None` | Bearer token. Falls back to `TRELLAR_API_KEY` |
|
|
162
|
+
| `timeout` | `float` | HTTP request timeout in seconds (default `30.0`) |
|
|
163
|
+
|
|
164
|
+
`context`, `trace_id`, and `agent_name` are resolved automatically from the active guard created by `get_agent_guard` — there is no way to pass them manually. Requests always go to `https://api.trellar.io`; callers cannot redirect them.
|
|
165
|
+
|
|
166
|
+
**Raises:**
|
|
167
|
+
- `ValueError` — if no active guard is found, its `trace_id` cannot be resolved, or `api_key` is missing
|
|
168
|
+
- `requests.HTTPError` — on non-2xx HTTP responses
|
|
169
|
+
|
|
170
|
+
### `AgentLoopResult`
|
|
171
|
+
|
|
172
|
+
A frozen dataclass with two fields:
|
|
173
|
+
|
|
174
|
+
| Field | Type | Description |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| `score` | `int` | Confidence score from 1 (low) to 10 (high) |
|
|
177
|
+
| `explanation` | `str` | Human-readable explanation of the score |
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "trellar"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Client library for the Trellar confidence evaluation API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Tomer Ben Harush" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["agent", "llm", "opentelemetry", "confidence", "ai"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"requests>=2.28",
|
|
28
|
+
"opentelemetry-sdk>=1.20",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
test = [
|
|
33
|
+
"pytest>=8.0",
|
|
34
|
+
]
|
|
35
|
+
langchain = [
|
|
36
|
+
"langchain-core>=0.1",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|
|
40
|
+
include = ["trellar*"]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/benarush/AITL"
|
|
44
|
+
"Bug Tracker" = "https://github.com/benarush/AITL/issues"
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
trellar-0.3.0/setup.cfg
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from trellar import evaluate_confidence, get_agent_guard
|
|
9
|
+
from trellar._context import _current_callback
|
|
10
|
+
from trellar.callbacks.langchain_callback import _AgentGuardCallback
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ---------------------------------------------------------------------------
|
|
14
|
+
# get_agent_guard — factory behaviour
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
class TestGetAgentGuard:
|
|
18
|
+
def test_returns_agent_guard_callback(self):
|
|
19
|
+
guard = get_agent_guard("research-agent")
|
|
20
|
+
assert isinstance(guard, _AgentGuardCallback)
|
|
21
|
+
|
|
22
|
+
def test_stores_agent_name(self):
|
|
23
|
+
guard = get_agent_guard("support-bot")
|
|
24
|
+
assert guard.agent_name == "support-bot"
|
|
25
|
+
|
|
26
|
+
def test_raises_on_empty_string(self):
|
|
27
|
+
with pytest.raises(ValueError, match="agent_name is required"):
|
|
28
|
+
get_agent_guard("")
|
|
29
|
+
|
|
30
|
+
def test_raises_on_blank_string(self):
|
|
31
|
+
with pytest.raises(ValueError, match="agent_name is required"):
|
|
32
|
+
get_agent_guard(" ")
|
|
33
|
+
|
|
34
|
+
def test_each_call_returns_new_instance(self):
|
|
35
|
+
a = get_agent_guard("my-agent")
|
|
36
|
+
b = get_agent_guard("my-agent")
|
|
37
|
+
assert a is not b
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
# _AgentGuardCallback — agent_name validation
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
class TestAgentGuardCallbackAgentName:
|
|
45
|
+
def test_stores_agent_name(self):
|
|
46
|
+
handler = _AgentGuardCallback(agent_name="my-graph")
|
|
47
|
+
assert handler.agent_name == "my-graph"
|
|
48
|
+
|
|
49
|
+
def test_agent_name_is_keyword_only(self):
|
|
50
|
+
with pytest.raises(TypeError):
|
|
51
|
+
_AgentGuardCallback("positional-name") # type: ignore[call-arg]
|
|
52
|
+
|
|
53
|
+
def test_raises_on_empty_name(self):
|
|
54
|
+
with pytest.raises(ValueError, match="agent_name is required"):
|
|
55
|
+
_AgentGuardCallback(agent_name="")
|
|
56
|
+
|
|
57
|
+
def test_error_message_is_descriptive(self):
|
|
58
|
+
with pytest.raises(ValueError, match="uniquely identifies"):
|
|
59
|
+
_AgentGuardCallback(agent_name="")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------------------
|
|
63
|
+
# evaluate_confidence — agent_name forwarded in payload
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
class TestEvaluateConfidenceAgentName:
|
|
67
|
+
@patch("trellar.agent_loop.requests.post")
|
|
68
|
+
def test_agent_name_included_in_payload(self, mock_post, mock_http_ok, active_handler):
|
|
69
|
+
mock_post.return_value = mock_http_ok
|
|
70
|
+
|
|
71
|
+
evaluate_confidence(api_key="key")
|
|
72
|
+
|
|
73
|
+
payload = mock_post.call_args.kwargs["json"]
|
|
74
|
+
assert payload["agent_name"] == "test-agent"
|
|
75
|
+
|
|
76
|
+
@patch("trellar.agent_loop.requests.post")
|
|
77
|
+
def test_agent_name_matches_guard(self, mock_post, mock_http_ok):
|
|
78
|
+
mock_post.return_value = mock_http_ok
|
|
79
|
+
|
|
80
|
+
guard = get_agent_guard("analytics-bot")
|
|
81
|
+
guard.trace_id = uuid.uuid4()
|
|
82
|
+
token = _current_callback.set(guard)
|
|
83
|
+
try:
|
|
84
|
+
evaluate_confidence(api_key="key")
|
|
85
|
+
payload = mock_post.call_args.kwargs["json"]
|
|
86
|
+
assert payload["agent_name"] == "analytics-bot"
|
|
87
|
+
finally:
|
|
88
|
+
_current_callback.reset(token)
|
|
89
|
+
|
|
90
|
+
@patch("trellar.agent_loop.requests.post")
|
|
91
|
+
def test_trace_id_also_in_payload(self, mock_post, mock_http_ok, active_handler):
|
|
92
|
+
mock_post.return_value = mock_http_ok
|
|
93
|
+
|
|
94
|
+
evaluate_confidence(api_key="key")
|
|
95
|
+
|
|
96
|
+
payload = mock_post.call_args.kwargs["json"]
|
|
97
|
+
assert payload["trace_id"] == str(active_handler.trace_id)
|
|
98
|
+
|
|
99
|
+
def test_raises_when_no_active_handler(self):
|
|
100
|
+
token = _current_callback.set(None)
|
|
101
|
+
try:
|
|
102
|
+
with pytest.raises(ValueError, match="No active callback handler"):
|
|
103
|
+
evaluate_confidence(api_key="key")
|
|
104
|
+
finally:
|
|
105
|
+
_current_callback.reset(token)
|