letta-client 0.1.53__py3-none-any.whl → 0.1.54__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.
Potentially problematic release.
This version of letta-client might be problematic. Click here for more details.
- letta_client/client.py +306 -0
- letta_client/core/client_wrapper.py +1 -1
- letta_client/runs/client.py +195 -0
- {letta_client-0.1.53.dist-info → letta_client-0.1.54.dist-info}/METADATA +1 -1
- {letta_client-0.1.53.dist-info → letta_client-0.1.54.dist-info}/RECORD +6 -6
- {letta_client-0.1.53.dist-info → letta_client-0.1.54.dist-info}/WHEEL +0 -0
letta_client/client.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import typing
|
|
3
|
+
from pydantic import BaseModel, Field, model_validator
|
|
3
4
|
from textwrap import dedent
|
|
5
|
+
from abc import abstractmethod
|
|
4
6
|
|
|
5
7
|
from .base_client import AsyncLettaBase, LettaBase
|
|
6
8
|
from .core.request_options import RequestOptions
|
|
@@ -25,12 +27,113 @@ class AsyncLetta(AsyncLettaBase):
|
|
|
25
27
|
self.tools = ToolsClient(client_wrapper=self._client_wrapper)
|
|
26
28
|
|
|
27
29
|
|
|
30
|
+
class BaseTool(Tool):
|
|
31
|
+
name: str = Field(..., description="The name of the function.")
|
|
32
|
+
args_schema: typing.Optional[typing.Type[BaseModel]] = Field(default=None, description="The schema for validating the tool's arguments.")
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def run(self, *args, **kwargs) -> typing.Any:
|
|
36
|
+
"""
|
|
37
|
+
Execute the tool with the provided arguments.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
self
|
|
42
|
+
The instance of the tool
|
|
43
|
+
*args
|
|
44
|
+
Positional arguments to pass to the tool.
|
|
45
|
+
**kwargs
|
|
46
|
+
Keyword arguments to pass to the tool.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
typing.Any
|
|
51
|
+
The result of executing the tool.
|
|
52
|
+
"""
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@model_validator(mode="after")
|
|
57
|
+
def no_self_in_run_source(self) -> "BaseTool":
|
|
58
|
+
"""
|
|
59
|
+
Validate that the provided implementation does not reference `self` in the
|
|
60
|
+
`run` method implementation.
|
|
61
|
+
|
|
62
|
+
This check is performed after the model is created, so `self` is guaranteed
|
|
63
|
+
to be set.
|
|
64
|
+
|
|
65
|
+
If `self` is found in the source code of the `run` method, a `ValueError` is
|
|
66
|
+
raised with a message pointing to the line and value of the offending code.
|
|
67
|
+
"""
|
|
68
|
+
source_code = self.get_source_code()
|
|
69
|
+
if "self." in source_code:
|
|
70
|
+
raise_on_line, line_value = None, None
|
|
71
|
+
for i, line in enumerate(source_code.splitlines()):
|
|
72
|
+
if "self." in line:
|
|
73
|
+
raise_on_line, line_value = i+1, line
|
|
74
|
+
break;
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"Detected reference to 'self' in line {raise_on_line} of implementation, " +
|
|
77
|
+
f"which is not allowed:\n\n{line_value}\n\n" +
|
|
78
|
+
f"Please pass in the arguments directly to run() instead.")
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_source_code(self) -> str:
|
|
83
|
+
"""
|
|
84
|
+
Get the source code of the `run` method, which will be executed in an agent step.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
str
|
|
89
|
+
The source code of the tool.
|
|
90
|
+
"""
|
|
91
|
+
source_code = dedent(inspect.getsource(self.run))
|
|
92
|
+
|
|
93
|
+
# replace tool name
|
|
94
|
+
source_code = source_code.replace("def run", f"def {self.name}")
|
|
95
|
+
|
|
96
|
+
# remove self, handling several cases
|
|
97
|
+
source_code_lines = source_code.splitlines()
|
|
98
|
+
if "self" in source_code_lines[0]:
|
|
99
|
+
# def run(self, ...): or def run (self,): or def run(self):
|
|
100
|
+
source_code_lines[0] = source_code_lines[0].replace("self, ", "").replace("self,", "").replace("self", "")
|
|
101
|
+
else:
|
|
102
|
+
maybe_line_to_delete = None
|
|
103
|
+
for i, line in enumerate(source_code_lines):
|
|
104
|
+
if line.strip() == "self" or line.strip() == "self,":
|
|
105
|
+
# def run(
|
|
106
|
+
# self,
|
|
107
|
+
# ...
|
|
108
|
+
# ):
|
|
109
|
+
maybe_line_to_delete = i
|
|
110
|
+
break
|
|
111
|
+
elif line.strip().startswith("self"):
|
|
112
|
+
# def run(
|
|
113
|
+
# self, ...
|
|
114
|
+
# ):
|
|
115
|
+
source_code_lines[i] = line.replace("self, ", "").replace("self,", "").replace("self", "")
|
|
116
|
+
break
|
|
117
|
+
if maybe_line_to_delete is not None:
|
|
118
|
+
del source_code_lines[maybe_line_to_delete]
|
|
119
|
+
if maybe_line_to_delete == 1 and source_code_lines[0].strip()[-1] == "(" and source_code_lines[1].strip()[0] == ")":
|
|
120
|
+
# def run(
|
|
121
|
+
# self
|
|
122
|
+
# ):
|
|
123
|
+
source_code_lines[0] = source_code_lines[0].strip() + source_code_lines[1].strip()
|
|
124
|
+
del source_code_lines[1]
|
|
125
|
+
|
|
126
|
+
source_code = "\n".join(source_code_lines)
|
|
127
|
+
return source_code
|
|
128
|
+
|
|
129
|
+
|
|
28
130
|
class ToolsClient(ToolsClientBase):
|
|
29
131
|
|
|
30
132
|
def create_from_function(
|
|
31
133
|
self,
|
|
32
134
|
*,
|
|
33
135
|
func: typing.Callable,
|
|
136
|
+
args_schema: typing.Optional[typing.Type[BaseModel]] = OMIT,
|
|
34
137
|
description: typing.Optional[str] = OMIT,
|
|
35
138
|
tags: typing.Optional[typing.Sequence[str]] = OMIT,
|
|
36
139
|
source_type: typing.Optional[str] = OMIT,
|
|
@@ -40,9 +143,72 @@ class ToolsClient(ToolsClientBase):
|
|
|
40
143
|
return_char_limit: typing.Optional[int] = OMIT,
|
|
41
144
|
request_options: typing.Optional[RequestOptions] = None,
|
|
42
145
|
) -> Tool:
|
|
146
|
+
"""
|
|
147
|
+
Create a new tool from a callable
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
func : typing.Callable
|
|
152
|
+
The callable to create the tool from.
|
|
153
|
+
|
|
154
|
+
args_schema : typing.Optional[typing.Type[BaseModel]]
|
|
155
|
+
The arguments schema of the function, as a Pydantic model.
|
|
156
|
+
|
|
157
|
+
description : typing.Optional[str]
|
|
158
|
+
The description of the tool.
|
|
159
|
+
|
|
160
|
+
tags : typing.Optional[typing.Sequence[str]]
|
|
161
|
+
Metadata tags.
|
|
162
|
+
|
|
163
|
+
source_type : typing.Optional[str]
|
|
164
|
+
The source type of the function.
|
|
165
|
+
|
|
166
|
+
json_schema : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
|
|
167
|
+
The JSON schema of the function (auto-generated from source_code if not provided)
|
|
168
|
+
|
|
169
|
+
return_char_limit : typing.Optional[int]
|
|
170
|
+
The maximum number of characters in the response.
|
|
171
|
+
|
|
172
|
+
request_options : typing.Optional[RequestOptions]
|
|
173
|
+
Request-specific configuration.
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
Tool
|
|
178
|
+
Successful Response
|
|
179
|
+
|
|
180
|
+
Examples
|
|
181
|
+
--------
|
|
182
|
+
from letta_client import Letta
|
|
183
|
+
|
|
184
|
+
client = Letta(
|
|
185
|
+
token="YOUR_TOKEN",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
def add_two_numbers(a: int, b: int) -> int:
|
|
189
|
+
return a + b
|
|
190
|
+
|
|
191
|
+
client.tools.create_from_function(
|
|
192
|
+
func=add_two_numbers,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
class InventoryEntryData(BaseModel):
|
|
196
|
+
data: InventoryEntry
|
|
197
|
+
quantity_change: int
|
|
198
|
+
|
|
199
|
+
def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
client.tools.create_from_function(
|
|
203
|
+
func=manage_inventory,
|
|
204
|
+
args_schema=InventoryEntryData,
|
|
205
|
+
)
|
|
206
|
+
"""
|
|
43
207
|
source_code = dedent(inspect.getsource(func))
|
|
208
|
+
args_json_schema = args_schema.model_json_schema() if args_schema and args_schema != OMIT else None
|
|
44
209
|
return self.create(
|
|
45
210
|
source_code=source_code,
|
|
211
|
+
args_json_schema=args_json_schema,
|
|
46
212
|
description=description,
|
|
47
213
|
tags=tags,
|
|
48
214
|
source_type=source_type,
|
|
@@ -51,10 +217,12 @@ class ToolsClient(ToolsClientBase):
|
|
|
51
217
|
request_options=request_options,
|
|
52
218
|
)
|
|
53
219
|
|
|
220
|
+
|
|
54
221
|
def upsert_from_function(
|
|
55
222
|
self,
|
|
56
223
|
*,
|
|
57
224
|
func: typing.Callable,
|
|
225
|
+
args_schema: typing.Optional[typing.Type[BaseModel]] = OMIT,
|
|
58
226
|
description: typing.Optional[str] = OMIT,
|
|
59
227
|
tags: typing.Optional[typing.Sequence[str]] = OMIT,
|
|
60
228
|
source_type: typing.Optional[str] = OMIT,
|
|
@@ -64,9 +232,72 @@ class ToolsClient(ToolsClientBase):
|
|
|
64
232
|
return_char_limit: typing.Optional[int] = OMIT,
|
|
65
233
|
request_options: typing.Optional[RequestOptions] = None,
|
|
66
234
|
) -> Tool:
|
|
235
|
+
"""
|
|
236
|
+
Create or update a tool from a callable
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
func : typing.Callable
|
|
241
|
+
The callable to create or update the tool from.
|
|
242
|
+
|
|
243
|
+
args_schema : typing.Optional[typing.Type[BaseModel]]
|
|
244
|
+
The arguments schema of the function, as a Pydantic model.
|
|
245
|
+
|
|
246
|
+
description : typing.Optional[str]
|
|
247
|
+
The description of the tool.
|
|
248
|
+
|
|
249
|
+
tags : typing.Optional[typing.Sequence[str]]
|
|
250
|
+
Metadata tags.
|
|
251
|
+
|
|
252
|
+
source_type : typing.Optional[str]
|
|
253
|
+
The source type of the function.
|
|
254
|
+
|
|
255
|
+
json_schema : typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]]
|
|
256
|
+
The JSON schema of the function (auto-generated from source_code if not provided)
|
|
257
|
+
|
|
258
|
+
return_char_limit : typing.Optional[int]
|
|
259
|
+
The maximum number of characters in the response.
|
|
260
|
+
|
|
261
|
+
request_options : typing.Optional[RequestOptions]
|
|
262
|
+
Request-specific configuration.
|
|
263
|
+
|
|
264
|
+
Returns
|
|
265
|
+
-------
|
|
266
|
+
Tool
|
|
267
|
+
Successful Response
|
|
268
|
+
|
|
269
|
+
Examples
|
|
270
|
+
--------
|
|
271
|
+
from letta_client import Letta
|
|
272
|
+
|
|
273
|
+
client = Letta(
|
|
274
|
+
token="YOUR_TOKEN",
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
def add_two_numbers(a: int, b: int) -> int:
|
|
278
|
+
return a + b
|
|
279
|
+
|
|
280
|
+
client.tools.upsert_from_function(
|
|
281
|
+
func=add_two_numbers,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
class InventoryEntryData(BaseModel):
|
|
285
|
+
data: InventoryEntry
|
|
286
|
+
quantity_change: int
|
|
287
|
+
|
|
288
|
+
def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
client.tools.upsert_from_function(
|
|
292
|
+
func=manage_inventory,
|
|
293
|
+
args_schema=InventoryEntryData,
|
|
294
|
+
)
|
|
295
|
+
"""
|
|
67
296
|
source_code = dedent(inspect.getsource(func))
|
|
297
|
+
args_json_schema = args_schema.model_json_schema() if args_schema and args_schema != OMIT else None
|
|
68
298
|
return self.upsert(
|
|
69
299
|
source_code=source_code,
|
|
300
|
+
args_json_schema=args_json_schema,
|
|
70
301
|
description=description,
|
|
71
302
|
tags=tags,
|
|
72
303
|
source_type=source_type,
|
|
@@ -74,3 +305,78 @@ class ToolsClient(ToolsClientBase):
|
|
|
74
305
|
return_char_limit=return_char_limit,
|
|
75
306
|
request_options=request_options,
|
|
76
307
|
)
|
|
308
|
+
|
|
309
|
+
def add(
|
|
310
|
+
self,
|
|
311
|
+
*,
|
|
312
|
+
tool: BaseTool,
|
|
313
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
314
|
+
) -> Tool:
|
|
315
|
+
"""
|
|
316
|
+
Add a tool to Letta from a custom Tool class
|
|
317
|
+
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
tool : BaseTool
|
|
321
|
+
The tool object to be added.
|
|
322
|
+
|
|
323
|
+
request_options : typing.Optional[RequestOptions]
|
|
324
|
+
Request-specific configuration.
|
|
325
|
+
|
|
326
|
+
Returns
|
|
327
|
+
-------
|
|
328
|
+
Tool
|
|
329
|
+
Successful Response
|
|
330
|
+
|
|
331
|
+
Examples
|
|
332
|
+
--------
|
|
333
|
+
from letta_client import Letta
|
|
334
|
+
|
|
335
|
+
client = Letta(
|
|
336
|
+
token="YOUR_TOKEN",
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
class InventoryItem(BaseModel):
|
|
340
|
+
sku: str # Unique product identifier
|
|
341
|
+
name: str # Product name
|
|
342
|
+
price: float # Current price
|
|
343
|
+
category: str # Product category (e.g., "Electronics", "Clothing")
|
|
344
|
+
|
|
345
|
+
class InventoryEntry(BaseModel):
|
|
346
|
+
timestamp: int # Unix timestamp of the transaction
|
|
347
|
+
item: InventoryItem # The product being updated
|
|
348
|
+
transaction_id: str # Unique identifier for this inventory update
|
|
349
|
+
|
|
350
|
+
class InventoryEntryData(BaseModel):
|
|
351
|
+
data: InventoryEntry
|
|
352
|
+
quantity_change: int # Change in quantity (positive for additions, negative for removals)
|
|
353
|
+
|
|
354
|
+
class ManageInventoryTool(BaseTool):
|
|
355
|
+
name: str = "manage_inventory"
|
|
356
|
+
args_schema: Type[BaseModel] = InventoryEntryData
|
|
357
|
+
description: str = "Update inventory catalogue with a new data entry"
|
|
358
|
+
tags: List[str] = ["inventory", "shop"]
|
|
359
|
+
|
|
360
|
+
def run(self, data: InventoryEntry, quantity_change: int) -> bool:
|
|
361
|
+
'''
|
|
362
|
+
Implementation of the manage_inventory tool
|
|
363
|
+
'''
|
|
364
|
+
print(f"Updated inventory for {data.item.name} with a quantity change of {quantity_change}")
|
|
365
|
+
return True
|
|
366
|
+
|
|
367
|
+
client.tools.add(
|
|
368
|
+
tool=ManageInventoryTool()
|
|
369
|
+
)
|
|
370
|
+
"""
|
|
371
|
+
source_code = tool.get_source_code()
|
|
372
|
+
args_json_schema = tool.args_schema.model_json_schema() if tool.args_schema else None
|
|
373
|
+
return self.upsert(
|
|
374
|
+
source_code=source_code,
|
|
375
|
+
args_json_schema=args_json_schema or OMIT,
|
|
376
|
+
description=tool.description or OMIT,
|
|
377
|
+
tags=tool.tags or OMIT,
|
|
378
|
+
source_type=tool.source_type or OMIT,
|
|
379
|
+
json_schema=tool.json_schema or OMIT,
|
|
380
|
+
return_char_limit=tool.return_char_limit or OMIT,
|
|
381
|
+
request_options=request_options,
|
|
382
|
+
)
|
|
@@ -16,7 +16,7 @@ class BaseClientWrapper:
|
|
|
16
16
|
headers: typing.Dict[str, str] = {
|
|
17
17
|
"X-Fern-Language": "Python",
|
|
18
18
|
"X-Fern-SDK-Name": "letta-client",
|
|
19
|
-
"X-Fern-SDK-Version": "0.1.
|
|
19
|
+
"X-Fern-SDK-Version": "0.1.54",
|
|
20
20
|
}
|
|
21
21
|
if self.token is not None:
|
|
22
22
|
headers["Authorization"] = f"Bearer {self.token}"
|
letta_client/runs/client.py
CHANGED
|
@@ -13,6 +13,7 @@ from ..core.jsonable_encoder import jsonable_encoder
|
|
|
13
13
|
from ..types.message_role import MessageRole
|
|
14
14
|
from ..types.letta_message_union import LettaMessageUnion
|
|
15
15
|
from ..types.usage_statistics import UsageStatistics
|
|
16
|
+
from ..types.step import Step
|
|
16
17
|
from ..core.client_wrapper import AsyncClientWrapper
|
|
17
18
|
|
|
18
19
|
|
|
@@ -395,6 +396,99 @@ class RunsClient:
|
|
|
395
396
|
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
396
397
|
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
397
398
|
|
|
399
|
+
def list_run_steps(
|
|
400
|
+
self,
|
|
401
|
+
run_id: str,
|
|
402
|
+
*,
|
|
403
|
+
before: typing.Optional[str] = None,
|
|
404
|
+
after: typing.Optional[str] = None,
|
|
405
|
+
limit: typing.Optional[int] = None,
|
|
406
|
+
order: typing.Optional[str] = None,
|
|
407
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
408
|
+
) -> typing.List[Step]:
|
|
409
|
+
"""
|
|
410
|
+
Get messages associated with a run with filtering options.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
run_id: ID of the run
|
|
414
|
+
before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list.
|
|
415
|
+
after: A cursor for use in pagination. `after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include after=obj_foo in order to fetch the next page of the list.
|
|
416
|
+
limit: Maximum number of steps to return
|
|
417
|
+
order: Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order.
|
|
418
|
+
|
|
419
|
+
Returns:
|
|
420
|
+
A list of steps associated with the run.
|
|
421
|
+
|
|
422
|
+
Parameters
|
|
423
|
+
----------
|
|
424
|
+
run_id : str
|
|
425
|
+
|
|
426
|
+
before : typing.Optional[str]
|
|
427
|
+
Cursor for pagination
|
|
428
|
+
|
|
429
|
+
after : typing.Optional[str]
|
|
430
|
+
Cursor for pagination
|
|
431
|
+
|
|
432
|
+
limit : typing.Optional[int]
|
|
433
|
+
Maximum number of messages to return
|
|
434
|
+
|
|
435
|
+
order : typing.Optional[str]
|
|
436
|
+
Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order.
|
|
437
|
+
|
|
438
|
+
request_options : typing.Optional[RequestOptions]
|
|
439
|
+
Request-specific configuration.
|
|
440
|
+
|
|
441
|
+
Returns
|
|
442
|
+
-------
|
|
443
|
+
typing.List[Step]
|
|
444
|
+
Successful Response
|
|
445
|
+
|
|
446
|
+
Examples
|
|
447
|
+
--------
|
|
448
|
+
from letta_client import Letta
|
|
449
|
+
|
|
450
|
+
client = Letta(
|
|
451
|
+
token="YOUR_TOKEN",
|
|
452
|
+
)
|
|
453
|
+
client.runs.list_run_steps(
|
|
454
|
+
run_id="run_id",
|
|
455
|
+
)
|
|
456
|
+
"""
|
|
457
|
+
_response = self._client_wrapper.httpx_client.request(
|
|
458
|
+
f"v1/runs/{jsonable_encoder(run_id)}/steps",
|
|
459
|
+
method="GET",
|
|
460
|
+
params={
|
|
461
|
+
"before": before,
|
|
462
|
+
"after": after,
|
|
463
|
+
"limit": limit,
|
|
464
|
+
"order": order,
|
|
465
|
+
},
|
|
466
|
+
request_options=request_options,
|
|
467
|
+
)
|
|
468
|
+
try:
|
|
469
|
+
if 200 <= _response.status_code < 300:
|
|
470
|
+
return typing.cast(
|
|
471
|
+
typing.List[Step],
|
|
472
|
+
construct_type(
|
|
473
|
+
type_=typing.List[Step], # type: ignore
|
|
474
|
+
object_=_response.json(),
|
|
475
|
+
),
|
|
476
|
+
)
|
|
477
|
+
if _response.status_code == 422:
|
|
478
|
+
raise UnprocessableEntityError(
|
|
479
|
+
typing.cast(
|
|
480
|
+
HttpValidationError,
|
|
481
|
+
construct_type(
|
|
482
|
+
type_=HttpValidationError, # type: ignore
|
|
483
|
+
object_=_response.json(),
|
|
484
|
+
),
|
|
485
|
+
)
|
|
486
|
+
)
|
|
487
|
+
_response_json = _response.json()
|
|
488
|
+
except JSONDecodeError:
|
|
489
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
490
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
491
|
+
|
|
398
492
|
|
|
399
493
|
class AsyncRunsClient:
|
|
400
494
|
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
|
@@ -822,3 +916,104 @@ class AsyncRunsClient:
|
|
|
822
916
|
except JSONDecodeError:
|
|
823
917
|
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
824
918
|
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
919
|
+
|
|
920
|
+
async def list_run_steps(
|
|
921
|
+
self,
|
|
922
|
+
run_id: str,
|
|
923
|
+
*,
|
|
924
|
+
before: typing.Optional[str] = None,
|
|
925
|
+
after: typing.Optional[str] = None,
|
|
926
|
+
limit: typing.Optional[int] = None,
|
|
927
|
+
order: typing.Optional[str] = None,
|
|
928
|
+
request_options: typing.Optional[RequestOptions] = None,
|
|
929
|
+
) -> typing.List[Step]:
|
|
930
|
+
"""
|
|
931
|
+
Get messages associated with a run with filtering options.
|
|
932
|
+
|
|
933
|
+
Args:
|
|
934
|
+
run_id: ID of the run
|
|
935
|
+
before: A cursor for use in pagination. `before` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include before=obj_foo in order to fetch the previous page of the list.
|
|
936
|
+
after: A cursor for use in pagination. `after` is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include after=obj_foo in order to fetch the next page of the list.
|
|
937
|
+
limit: Maximum number of steps to return
|
|
938
|
+
order: Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order.
|
|
939
|
+
|
|
940
|
+
Returns:
|
|
941
|
+
A list of steps associated with the run.
|
|
942
|
+
|
|
943
|
+
Parameters
|
|
944
|
+
----------
|
|
945
|
+
run_id : str
|
|
946
|
+
|
|
947
|
+
before : typing.Optional[str]
|
|
948
|
+
Cursor for pagination
|
|
949
|
+
|
|
950
|
+
after : typing.Optional[str]
|
|
951
|
+
Cursor for pagination
|
|
952
|
+
|
|
953
|
+
limit : typing.Optional[int]
|
|
954
|
+
Maximum number of messages to return
|
|
955
|
+
|
|
956
|
+
order : typing.Optional[str]
|
|
957
|
+
Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order.
|
|
958
|
+
|
|
959
|
+
request_options : typing.Optional[RequestOptions]
|
|
960
|
+
Request-specific configuration.
|
|
961
|
+
|
|
962
|
+
Returns
|
|
963
|
+
-------
|
|
964
|
+
typing.List[Step]
|
|
965
|
+
Successful Response
|
|
966
|
+
|
|
967
|
+
Examples
|
|
968
|
+
--------
|
|
969
|
+
import asyncio
|
|
970
|
+
|
|
971
|
+
from letta_client import AsyncLetta
|
|
972
|
+
|
|
973
|
+
client = AsyncLetta(
|
|
974
|
+
token="YOUR_TOKEN",
|
|
975
|
+
)
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
async def main() -> None:
|
|
979
|
+
await client.runs.list_run_steps(
|
|
980
|
+
run_id="run_id",
|
|
981
|
+
)
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
asyncio.run(main())
|
|
985
|
+
"""
|
|
986
|
+
_response = await self._client_wrapper.httpx_client.request(
|
|
987
|
+
f"v1/runs/{jsonable_encoder(run_id)}/steps",
|
|
988
|
+
method="GET",
|
|
989
|
+
params={
|
|
990
|
+
"before": before,
|
|
991
|
+
"after": after,
|
|
992
|
+
"limit": limit,
|
|
993
|
+
"order": order,
|
|
994
|
+
},
|
|
995
|
+
request_options=request_options,
|
|
996
|
+
)
|
|
997
|
+
try:
|
|
998
|
+
if 200 <= _response.status_code < 300:
|
|
999
|
+
return typing.cast(
|
|
1000
|
+
typing.List[Step],
|
|
1001
|
+
construct_type(
|
|
1002
|
+
type_=typing.List[Step], # type: ignore
|
|
1003
|
+
object_=_response.json(),
|
|
1004
|
+
),
|
|
1005
|
+
)
|
|
1006
|
+
if _response.status_code == 422:
|
|
1007
|
+
raise UnprocessableEntityError(
|
|
1008
|
+
typing.cast(
|
|
1009
|
+
HttpValidationError,
|
|
1010
|
+
construct_type(
|
|
1011
|
+
type_=HttpValidationError, # type: ignore
|
|
1012
|
+
object_=_response.json(),
|
|
1013
|
+
),
|
|
1014
|
+
)
|
|
1015
|
+
)
|
|
1016
|
+
_response_json = _response.json()
|
|
1017
|
+
except JSONDecodeError:
|
|
1018
|
+
raise ApiError(status_code=_response.status_code, body=_response.text)
|
|
1019
|
+
raise ApiError(status_code=_response.status_code, body=_response_json)
|
|
@@ -206,10 +206,10 @@ letta_client/agents/types/update_agent_tool_rules_item.py,sha256=gCA9oFxIWEcbVV5
|
|
|
206
206
|
letta_client/base_client.py,sha256=ZD62gkVcq-3piS6Az6L9yM9vD1kssEdtK3c0pHoRWMI,8395
|
|
207
207
|
letta_client/blocks/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
|
208
208
|
letta_client/blocks/client.py,sha256=AeQQ-IdYhV-zqLTt3PTrJOtJ6XtBZcXNC108Y5EogVU,29178
|
|
209
|
-
letta_client/client.py,sha256=
|
|
209
|
+
letta_client/client.py,sha256=xdSrD4IkWokZHujowd1r7zESBoVgKGNvo6RqgZ3f0Fg,12808
|
|
210
210
|
letta_client/core/__init__.py,sha256=OKbX2aCZXgHCDUsCouqv-OiX32xA6eFFCKIUH9M5Vzk,1591
|
|
211
211
|
letta_client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
|
212
|
-
letta_client/core/client_wrapper.py,sha256=
|
|
212
|
+
letta_client/core/client_wrapper.py,sha256=jIg6jkb0yX5-JmMNEd_l26MVdszs6wxY2UDbBauoiZM,1997
|
|
213
213
|
letta_client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
|
214
214
|
letta_client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
|
215
215
|
letta_client/core/http_client.py,sha256=siUQ6UV0ARZALlxubqWSSAAPC9B4VW8y6MGlHStfaeo,19552
|
|
@@ -238,7 +238,7 @@ letta_client/providers/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAK
|
|
|
238
238
|
letta_client/providers/client.py,sha256=RLpTHd9iQ5wlZqYEG4cF8YsDCdaQZ0odCFprukauCuc,18228
|
|
239
239
|
letta_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
240
240
|
letta_client/runs/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
|
241
|
-
letta_client/runs/client.py,sha256=
|
|
241
|
+
letta_client/runs/client.py,sha256=fu6RNu6qkG5kOkT7rfIjeuHp_REW5ZGxNwzFqTmhb-o,34546
|
|
242
242
|
letta_client/sources/__init__.py,sha256=kswgCv4UdkSVk1Y4tsMM1HadOwvhh_Fr96VTSMV4Umc,128
|
|
243
243
|
letta_client/sources/client.py,sha256=GbMg3ZR0JufGPOfYiptr9yDWKJ0FgT6zLD_k6fET0zs,28223
|
|
244
244
|
letta_client/sources/files/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
|
@@ -590,6 +590,6 @@ letta_client/voice/__init__.py,sha256=ZrZEuXIukVGhsfM-i0dIFfqjeSOBMPeEgDva7Vvnip
|
|
|
590
590
|
letta_client/voice/client.py,sha256=j3feSlNzeTVFXE7RUKEHGeMl_w0TJFBRUI3pXpLpUEI,6148
|
|
591
591
|
letta_client/voice/types/__init__.py,sha256=hBLJcrom99DkDxxsVRU2ni8kPx6SsCy8gtAJvNOz26w,199
|
|
592
592
|
letta_client/voice/types/create_voice_chat_completions_request.py,sha256=K4__83rXRCshfdobyAmH-5fUDJQ_PeSQetTUeC4Abk0,381
|
|
593
|
-
letta_client-0.1.
|
|
594
|
-
letta_client-0.1.
|
|
595
|
-
letta_client-0.1.
|
|
593
|
+
letta_client-0.1.54.dist-info/METADATA,sha256=bW_vwYxfAnY-_zb45lt9yg3s6H2EPpIUYK77NsOpqxo,4942
|
|
594
|
+
letta_client-0.1.54.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
|
595
|
+
letta_client-0.1.54.dist-info/RECORD,,
|
|
File without changes
|