tracia 0.0.1__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- tracia/__init__.py +152 -3
- tracia/_client.py +1100 -0
- tracia/_constants.py +39 -0
- tracia/_errors.py +87 -0
- tracia/_http.py +362 -0
- tracia/_llm.py +898 -0
- tracia/_session.py +244 -0
- tracia/_streaming.py +135 -0
- tracia/_types.py +564 -0
- tracia/_utils.py +116 -0
- tracia/py.typed +0 -0
- tracia/resources/__init__.py +6 -0
- tracia/resources/prompts.py +273 -0
- tracia/resources/spans.py +227 -0
- tracia-0.1.1.dist-info/METADATA +277 -0
- tracia-0.1.1.dist-info/RECORD +18 -0
- tracia-0.0.1.dist-info/METADATA +0 -52
- tracia-0.0.1.dist-info/RECORD +0 -5
- {tracia-0.0.1.dist-info → tracia-0.1.1.dist-info}/WHEEL +0 -0
- {tracia-0.0.1.dist-info → tracia-0.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"""Prompts API resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from .._types import (
|
|
9
|
+
CreatePromptOptions,
|
|
10
|
+
Prompt,
|
|
11
|
+
PromptListItem,
|
|
12
|
+
RunOptions,
|
|
13
|
+
RunResult,
|
|
14
|
+
UpdatePromptOptions,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from .._http import AsyncHttpClient, HttpClient
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Prompts:
|
|
22
|
+
"""Prompts API resource for managing prompt templates."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
client: "HttpClient",
|
|
27
|
+
async_client: "AsyncHttpClient | None" = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize the Prompts resource.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
client: The synchronous HTTP client.
|
|
33
|
+
async_client: Optional async HTTP client.
|
|
34
|
+
"""
|
|
35
|
+
self._client = client
|
|
36
|
+
self._async_client = async_client
|
|
37
|
+
|
|
38
|
+
def list(self) -> list[PromptListItem]:
|
|
39
|
+
"""List all prompts.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
The list of prompts.
|
|
43
|
+
|
|
44
|
+
Raises:
|
|
45
|
+
TraciaError: If the request fails.
|
|
46
|
+
"""
|
|
47
|
+
data = self._client.get("/api/v1/prompts")
|
|
48
|
+
return [PromptListItem.model_validate(item) for item in data["prompts"]]
|
|
49
|
+
|
|
50
|
+
async def alist(self) -> list[PromptListItem]:
|
|
51
|
+
"""List all prompts asynchronously.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
The list of prompts.
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
TraciaError: If the request fails.
|
|
58
|
+
"""
|
|
59
|
+
if self._async_client is None:
|
|
60
|
+
raise RuntimeError("Async client not initialized")
|
|
61
|
+
|
|
62
|
+
data = await self._async_client.get("/api/v1/prompts")
|
|
63
|
+
return [PromptListItem.model_validate(item) for item in data["prompts"]]
|
|
64
|
+
|
|
65
|
+
def get(self, slug: str) -> Prompt:
|
|
66
|
+
"""Get a prompt by slug.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
slug: The prompt slug.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The prompt.
|
|
73
|
+
|
|
74
|
+
Raises:
|
|
75
|
+
TraciaError: If the request fails.
|
|
76
|
+
"""
|
|
77
|
+
data = self._client.get(f"/api/v1/prompts/{quote(slug, safe='')}")
|
|
78
|
+
return Prompt.model_validate(data)
|
|
79
|
+
|
|
80
|
+
async def aget(self, slug: str) -> Prompt:
|
|
81
|
+
"""Get a prompt by slug asynchronously.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
slug: The prompt slug.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The prompt.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
TraciaError: If the request fails.
|
|
91
|
+
"""
|
|
92
|
+
if self._async_client is None:
|
|
93
|
+
raise RuntimeError("Async client not initialized")
|
|
94
|
+
|
|
95
|
+
data = await self._async_client.get(f"/api/v1/prompts/{quote(slug, safe='')}")
|
|
96
|
+
return Prompt.model_validate(data)
|
|
97
|
+
|
|
98
|
+
def create(self, options: CreatePromptOptions) -> Prompt:
|
|
99
|
+
"""Create a new prompt.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
options: The prompt creation options.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The created prompt.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
TraciaError: If the request fails.
|
|
109
|
+
"""
|
|
110
|
+
data = self._client.post(
|
|
111
|
+
"/api/v1/prompts",
|
|
112
|
+
options.model_dump(by_alias=True, exclude_none=True),
|
|
113
|
+
)
|
|
114
|
+
return Prompt.model_validate(data)
|
|
115
|
+
|
|
116
|
+
async def acreate(self, options: CreatePromptOptions) -> Prompt:
|
|
117
|
+
"""Create a new prompt asynchronously.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
options: The prompt creation options.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
The created prompt.
|
|
124
|
+
|
|
125
|
+
Raises:
|
|
126
|
+
TraciaError: If the request fails.
|
|
127
|
+
"""
|
|
128
|
+
if self._async_client is None:
|
|
129
|
+
raise RuntimeError("Async client not initialized")
|
|
130
|
+
|
|
131
|
+
data = await self._async_client.post(
|
|
132
|
+
"/api/v1/prompts",
|
|
133
|
+
options.model_dump(by_alias=True, exclude_none=True),
|
|
134
|
+
)
|
|
135
|
+
return Prompt.model_validate(data)
|
|
136
|
+
|
|
137
|
+
def update(self, slug: str, options: UpdatePromptOptions) -> Prompt:
|
|
138
|
+
"""Update an existing prompt.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
slug: The prompt slug.
|
|
142
|
+
options: The update options.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
The updated prompt.
|
|
146
|
+
|
|
147
|
+
Raises:
|
|
148
|
+
TraciaError: If the request fails.
|
|
149
|
+
"""
|
|
150
|
+
data = self._client.put(
|
|
151
|
+
f"/api/v1/prompts/{quote(slug, safe='')}",
|
|
152
|
+
options.model_dump(by_alias=True, exclude_none=True),
|
|
153
|
+
)
|
|
154
|
+
return Prompt.model_validate(data)
|
|
155
|
+
|
|
156
|
+
async def aupdate(self, slug: str, options: UpdatePromptOptions) -> Prompt:
|
|
157
|
+
"""Update an existing prompt asynchronously.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
slug: The prompt slug.
|
|
161
|
+
options: The update options.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
The updated prompt.
|
|
165
|
+
|
|
166
|
+
Raises:
|
|
167
|
+
TraciaError: If the request fails.
|
|
168
|
+
"""
|
|
169
|
+
if self._async_client is None:
|
|
170
|
+
raise RuntimeError("Async client not initialized")
|
|
171
|
+
|
|
172
|
+
data = await self._async_client.put(
|
|
173
|
+
f"/api/v1/prompts/{quote(slug, safe='')}",
|
|
174
|
+
options.model_dump(by_alias=True, exclude_none=True),
|
|
175
|
+
)
|
|
176
|
+
return Prompt.model_validate(data)
|
|
177
|
+
|
|
178
|
+
def delete(self, slug: str) -> None:
|
|
179
|
+
"""Delete a prompt.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
slug: The prompt slug.
|
|
183
|
+
|
|
184
|
+
Raises:
|
|
185
|
+
TraciaError: If the request fails.
|
|
186
|
+
"""
|
|
187
|
+
self._client.delete(f"/api/v1/prompts/{quote(slug, safe='')}")
|
|
188
|
+
|
|
189
|
+
async def adelete(self, slug: str) -> None:
|
|
190
|
+
"""Delete a prompt asynchronously.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
slug: The prompt slug.
|
|
194
|
+
|
|
195
|
+
Raises:
|
|
196
|
+
TraciaError: If the request fails.
|
|
197
|
+
"""
|
|
198
|
+
if self._async_client is None:
|
|
199
|
+
raise RuntimeError("Async client not initialized")
|
|
200
|
+
|
|
201
|
+
await self._async_client.delete(f"/api/v1/prompts/{quote(slug, safe='')}")
|
|
202
|
+
|
|
203
|
+
def run(
|
|
204
|
+
self,
|
|
205
|
+
slug: str,
|
|
206
|
+
variables: dict[str, str] | None = None,
|
|
207
|
+
options: RunOptions | None = None,
|
|
208
|
+
) -> RunResult:
|
|
209
|
+
"""Run a prompt template.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
slug: The prompt slug.
|
|
213
|
+
variables: Optional variables to interpolate.
|
|
214
|
+
options: Optional run options.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The run result.
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
TraciaError: If the request fails.
|
|
221
|
+
"""
|
|
222
|
+
body = self._build_run_body(variables, options)
|
|
223
|
+
data = self._client.post(f"/api/v1/prompts/{quote(slug, safe='')}/run", body)
|
|
224
|
+
return RunResult.model_validate(data)
|
|
225
|
+
|
|
226
|
+
async def arun(
|
|
227
|
+
self,
|
|
228
|
+
slug: str,
|
|
229
|
+
variables: dict[str, str] | None = None,
|
|
230
|
+
options: RunOptions | None = None,
|
|
231
|
+
) -> RunResult:
|
|
232
|
+
"""Run a prompt template asynchronously.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
slug: The prompt slug.
|
|
236
|
+
variables: Optional variables to interpolate.
|
|
237
|
+
options: Optional run options.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
The run result.
|
|
241
|
+
|
|
242
|
+
Raises:
|
|
243
|
+
TraciaError: If the request fails.
|
|
244
|
+
"""
|
|
245
|
+
if self._async_client is None:
|
|
246
|
+
raise RuntimeError("Async client not initialized")
|
|
247
|
+
|
|
248
|
+
body = self._build_run_body(variables, options)
|
|
249
|
+
data = await self._async_client.post(f"/api/v1/prompts/{quote(slug, safe='')}/run", body)
|
|
250
|
+
return RunResult.model_validate(data)
|
|
251
|
+
|
|
252
|
+
def _build_run_body(
|
|
253
|
+
self,
|
|
254
|
+
variables: dict[str, str] | None,
|
|
255
|
+
options: RunOptions | None,
|
|
256
|
+
) -> dict[str, Any]:
|
|
257
|
+
"""Build the request body for the run endpoint."""
|
|
258
|
+
body: dict[str, Any] = {}
|
|
259
|
+
|
|
260
|
+
if variables:
|
|
261
|
+
body["variables"] = variables
|
|
262
|
+
|
|
263
|
+
if options:
|
|
264
|
+
if options.model is not None:
|
|
265
|
+
body["model"] = options.model
|
|
266
|
+
if options.tags is not None:
|
|
267
|
+
body["tags"] = options.tags
|
|
268
|
+
if options.user_id is not None:
|
|
269
|
+
body["userId"] = options.user_id
|
|
270
|
+
if options.session_id is not None:
|
|
271
|
+
body["sessionId"] = options.session_id
|
|
272
|
+
|
|
273
|
+
return body
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Spans API resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from .._types import (
|
|
9
|
+
CreateSpanPayload,
|
|
10
|
+
CreateSpanResult,
|
|
11
|
+
EvaluateOptions,
|
|
12
|
+
EvaluateResult,
|
|
13
|
+
ListSpansOptions,
|
|
14
|
+
ListSpansResult,
|
|
15
|
+
Span,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from .._http import AsyncHttpClient, HttpClient
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Spans:
|
|
23
|
+
"""Spans API resource for managing trace spans."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
client: "HttpClient",
|
|
28
|
+
async_client: "AsyncHttpClient | None" = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Initialize the Spans resource.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
client: The synchronous HTTP client.
|
|
34
|
+
async_client: Optional async HTTP client.
|
|
35
|
+
"""
|
|
36
|
+
self._client = client
|
|
37
|
+
self._async_client = async_client
|
|
38
|
+
|
|
39
|
+
def create(self, payload: CreateSpanPayload) -> CreateSpanResult:
|
|
40
|
+
"""Create a new span.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
payload: The span creation payload.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
The created span result.
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
TraciaError: If the request fails.
|
|
50
|
+
"""
|
|
51
|
+
data = self._client.post(
|
|
52
|
+
"/api/v1/spans",
|
|
53
|
+
payload.model_dump(by_alias=True, exclude_none=True),
|
|
54
|
+
)
|
|
55
|
+
return CreateSpanResult.model_validate(data)
|
|
56
|
+
|
|
57
|
+
async def acreate(self, payload: CreateSpanPayload) -> CreateSpanResult:
|
|
58
|
+
"""Create a new span asynchronously.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
payload: The span creation payload.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
The created span result.
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
TraciaError: If the request fails.
|
|
68
|
+
"""
|
|
69
|
+
if self._async_client is None:
|
|
70
|
+
raise RuntimeError("Async client not initialized")
|
|
71
|
+
|
|
72
|
+
data = await self._async_client.post(
|
|
73
|
+
"/api/v1/spans",
|
|
74
|
+
payload.model_dump(by_alias=True, exclude_none=True),
|
|
75
|
+
)
|
|
76
|
+
return CreateSpanResult.model_validate(data)
|
|
77
|
+
|
|
78
|
+
def get(self, span_id: str) -> Span:
|
|
79
|
+
"""Get a span by ID.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
span_id: The span ID.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The span.
|
|
86
|
+
|
|
87
|
+
Raises:
|
|
88
|
+
TraciaError: If the request fails.
|
|
89
|
+
"""
|
|
90
|
+
data = self._client.get(f"/api/v1/spans/{quote(span_id, safe='')}")
|
|
91
|
+
return Span.model_validate(data)
|
|
92
|
+
|
|
93
|
+
async def aget(self, span_id: str) -> Span:
|
|
94
|
+
"""Get a span by ID asynchronously.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
span_id: The span ID.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The span.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
TraciaError: If the request fails.
|
|
104
|
+
"""
|
|
105
|
+
if self._async_client is None:
|
|
106
|
+
raise RuntimeError("Async client not initialized")
|
|
107
|
+
|
|
108
|
+
data = await self._async_client.get(f"/api/v1/spans/{quote(span_id, safe='')}")
|
|
109
|
+
return Span.model_validate(data)
|
|
110
|
+
|
|
111
|
+
def list(self, options: ListSpansOptions | None = None) -> ListSpansResult:
|
|
112
|
+
"""List spans with optional filtering.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
options: Optional filtering and pagination options.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
The list of spans.
|
|
119
|
+
|
|
120
|
+
Raises:
|
|
121
|
+
TraciaError: If the request fails.
|
|
122
|
+
"""
|
|
123
|
+
params = self._build_list_params(options)
|
|
124
|
+
data = self._client.get("/api/v1/spans", params=params)
|
|
125
|
+
return ListSpansResult.model_validate(data)
|
|
126
|
+
|
|
127
|
+
async def alist(self, options: ListSpansOptions | None = None) -> ListSpansResult:
|
|
128
|
+
"""List spans asynchronously with optional filtering.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
options: Optional filtering and pagination options.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
The list of spans.
|
|
135
|
+
|
|
136
|
+
Raises:
|
|
137
|
+
TraciaError: If the request fails.
|
|
138
|
+
"""
|
|
139
|
+
if self._async_client is None:
|
|
140
|
+
raise RuntimeError("Async client not initialized")
|
|
141
|
+
|
|
142
|
+
params = self._build_list_params(options)
|
|
143
|
+
data = await self._async_client.get("/api/v1/spans", params=params)
|
|
144
|
+
return ListSpansResult.model_validate(data)
|
|
145
|
+
|
|
146
|
+
def _build_list_params(
|
|
147
|
+
self, options: ListSpansOptions | None
|
|
148
|
+
) -> dict[str, Any] | None:
|
|
149
|
+
"""Build query parameters for list endpoint."""
|
|
150
|
+
if options is None:
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
params: dict[str, Any] = {}
|
|
154
|
+
|
|
155
|
+
if options.prompt_slug is not None:
|
|
156
|
+
params["promptSlug"] = options.prompt_slug
|
|
157
|
+
if options.status is not None:
|
|
158
|
+
params["status"] = options.status
|
|
159
|
+
if options.start_date is not None:
|
|
160
|
+
params["startDate"] = options.start_date.isoformat()
|
|
161
|
+
if options.end_date is not None:
|
|
162
|
+
params["endDate"] = options.end_date.isoformat()
|
|
163
|
+
if options.user_id is not None:
|
|
164
|
+
params["userId"] = options.user_id
|
|
165
|
+
if options.session_id is not None:
|
|
166
|
+
params["sessionId"] = options.session_id
|
|
167
|
+
if options.tags is not None and len(options.tags) > 0:
|
|
168
|
+
params["tags"] = ",".join(options.tags)
|
|
169
|
+
if options.limit is not None:
|
|
170
|
+
params["limit"] = options.limit
|
|
171
|
+
if options.cursor is not None:
|
|
172
|
+
params["cursor"] = options.cursor
|
|
173
|
+
|
|
174
|
+
return params if params else None
|
|
175
|
+
|
|
176
|
+
def evaluate(self, span_id: str, options: EvaluateOptions) -> EvaluateResult:
|
|
177
|
+
"""Evaluate a span.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
span_id: The span ID to evaluate.
|
|
181
|
+
options: The evaluation options.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
The evaluation result.
|
|
185
|
+
|
|
186
|
+
Raises:
|
|
187
|
+
TraciaError: If the request fails.
|
|
188
|
+
"""
|
|
189
|
+
body = {
|
|
190
|
+
"evaluatorKey": options.evaluator,
|
|
191
|
+
"value": options.value,
|
|
192
|
+
}
|
|
193
|
+
if options.note is not None:
|
|
194
|
+
body["note"] = options.note
|
|
195
|
+
|
|
196
|
+
data = self._client.post(f"/api/v1/spans/{quote(span_id, safe='')}/evaluations", body)
|
|
197
|
+
return EvaluateResult.model_validate(data)
|
|
198
|
+
|
|
199
|
+
async def aevaluate(
|
|
200
|
+
self, span_id: str, options: EvaluateOptions
|
|
201
|
+
) -> EvaluateResult:
|
|
202
|
+
"""Evaluate a span asynchronously.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
span_id: The span ID to evaluate.
|
|
206
|
+
options: The evaluation options.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
The evaluation result.
|
|
210
|
+
|
|
211
|
+
Raises:
|
|
212
|
+
TraciaError: If the request fails.
|
|
213
|
+
"""
|
|
214
|
+
if self._async_client is None:
|
|
215
|
+
raise RuntimeError("Async client not initialized")
|
|
216
|
+
|
|
217
|
+
body = {
|
|
218
|
+
"evaluatorKey": options.evaluator,
|
|
219
|
+
"value": options.value,
|
|
220
|
+
}
|
|
221
|
+
if options.note is not None:
|
|
222
|
+
body["note"] = options.note
|
|
223
|
+
|
|
224
|
+
data = await self._async_client.post(
|
|
225
|
+
f"/api/v1/spans/{quote(span_id, safe='')}/evaluations", body
|
|
226
|
+
)
|
|
227
|
+
return EvaluateResult.model_validate(data)
|