letta-client 1.0.0a9__py3-none-any.whl → 1.0.0a11__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.

Files changed (63) hide show
  1. letta_client/_client.py +5 -1
  2. letta_client/_streaming.py +40 -2
  3. letta_client/_version.py +1 -1
  4. letta_client/resources/agents/agents.py +396 -396
  5. letta_client/resources/agents/blocks.py +198 -190
  6. letta_client/resources/agents/files.py +10 -13
  7. letta_client/resources/agents/folders.py +10 -13
  8. letta_client/resources/agents/messages.py +380 -370
  9. letta_client/resources/agents/tools.py +10 -13
  10. letta_client/resources/archives.py +111 -113
  11. letta_client/resources/batches/batches.py +10 -12
  12. letta_client/resources/batches/messages.py +11 -14
  13. letta_client/resources/blocks/blocks.py +238 -222
  14. letta_client/resources/folders/agents.py +10 -13
  15. letta_client/resources/folders/files.py +9 -12
  16. letta_client/resources/folders/folders.py +143 -145
  17. letta_client/resources/groups/groups.py +141 -141
  18. letta_client/resources/groups/messages.py +198 -198
  19. letta_client/resources/identities/blocks.py +7 -7
  20. letta_client/resources/identities/identities.py +151 -153
  21. letta_client/resources/runs/runs.py +11 -13
  22. letta_client/resources/tags.py +10 -13
  23. letta_client/resources/tools.py +802 -204
  24. letta_client/types/__init__.py +14 -7
  25. letta_client/types/{agent_update_params.py → agent_modify_params.py} +2 -2
  26. letta_client/types/agent_state.py +6 -3
  27. letta_client/types/agents/__init__.py +5 -3
  28. letta_client/types/agents/block.py +6 -3
  29. letta_client/types/agents/{block_update_params.py → block_modify_params.py} +8 -5
  30. letta_client/types/agents/file_list_response.py +14 -3
  31. letta_client/types/agents/folder_list_response.py +7 -3
  32. letta_client/types/agents/letta_streaming_response.py +70 -0
  33. letta_client/types/agents/{message_update_params.py → message_modify_params.py} +2 -2
  34. letta_client/types/agents/{message_update_response.py → message_modify_response.py} +2 -2
  35. letta_client/types/agents/tool_list_response.py +10 -0
  36. letta_client/types/archive_list_response.py +10 -0
  37. letta_client/types/{archive_update_params.py → archive_modify_params.py} +2 -2
  38. letta_client/types/batch_list_response.py +10 -0
  39. letta_client/types/batches/__init__.py +1 -0
  40. letta_client/types/batches/message_list_response.py +12 -0
  41. letta_client/types/block_create_params.py +6 -3
  42. letta_client/types/{block_update_params.py → block_modify_params.py} +8 -5
  43. letta_client/types/block_response.py +63 -0
  44. letta_client/types/create_block_param.py +6 -3
  45. letta_client/types/folder_list_response.py +10 -0
  46. letta_client/types/{folder_update_params.py → folder_modify_params.py} +2 -2
  47. letta_client/types/folders/agent_list_response.py +2 -1
  48. letta_client/types/folders/file_list_response.py +7 -4
  49. letta_client/types/{group_update_params.py → group_modify_params.py} +2 -2
  50. letta_client/types/groups/__init__.py +2 -2
  51. letta_client/types/groups/{message_update_params.py → message_modify_params.py} +2 -2
  52. letta_client/types/groups/{message_update_response.py → message_modify_response.py} +2 -2
  53. letta_client/types/identity_list_response.py +10 -0
  54. letta_client/types/{identity_update_params.py → identity_modify_params.py} +2 -2
  55. letta_client/types/run_list_response.py +10 -0
  56. letta_client/types/tag_list_response.py +2 -1
  57. letta_client/types/tool.py +106 -2
  58. letta_client/types/tool_list_response.py +10 -0
  59. letta_client/types/{tool_update_params.py → tool_modify_params.py} +2 -2
  60. {letta_client-1.0.0a9.dist-info → letta_client-1.0.0a11.dist-info}/METADATA +1 -1
  61. {letta_client-1.0.0a9.dist-info → letta_client-1.0.0a11.dist-info}/RECORD +63 -53
  62. {letta_client-1.0.0a9.dist-info → letta_client-1.0.0a11.dist-info}/WHEEL +0 -0
  63. {letta_client-1.0.0a9.dist-info → letta_client-1.0.0a11.dist-info}/licenses/LICENSE +0 -0
@@ -7,7 +7,7 @@ from typing_extensions import Literal
7
7
 
8
8
  import httpx
9
9
 
10
- from ..types import tool_list_params, tool_count_params, tool_create_params, tool_update_params, tool_upsert_params
10
+ from ..types import tool_list_params, tool_count_params, tool_create_params, tool_modify_params, tool_upsert_params
11
11
  from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
12
12
  from .._utils import maybe_transform, async_maybe_transform
13
13
  from .._compat import cached_property
@@ -18,13 +18,17 @@ from .._response import (
18
18
  async_to_raw_response_wrapper,
19
19
  async_to_streamed_response_wrapper,
20
20
  )
21
- from ..pagination import SyncArrayPage, AsyncArrayPage
22
- from ..types.tool import Tool
23
- from .._base_client import AsyncPaginator, make_request_options
21
+ from ..types.tool import Tool, BaseTool
22
+ from .._base_client import make_request_options
23
+ from ..types.tool_list_response import ToolListResponse
24
24
  from ..types.tool_count_response import ToolCountResponse
25
25
  from ..types.npm_requirement_param import NpmRequirementParam
26
26
  from ..types.pip_requirement_param import PipRequirementParam
27
27
  from ..types.tool_upsert_base_tools_response import ToolUpsertBaseToolsResponse
28
+ import typing
29
+ from pydantic import BaseModel
30
+ from textwrap import dedent
31
+ import inspect
28
32
 
29
33
  __all__ = ["ToolsResource", "AsyncToolsResource"]
30
34
 
@@ -165,96 +169,6 @@ class ToolsResource(SyncAPIResource):
165
169
  cast_to=Tool,
166
170
  )
167
171
 
168
- def update(
169
- self,
170
- tool_id: str,
171
- *,
172
- args_json_schema: Optional[Dict[str, object]] | Omit = omit,
173
- default_requires_approval: Optional[bool] | Omit = omit,
174
- description: Optional[str] | Omit = omit,
175
- enable_parallel_execution: Optional[bool] | Omit = omit,
176
- json_schema: Optional[Dict[str, object]] | Omit = omit,
177
- metadata: Optional[Dict[str, object]] | Omit = omit,
178
- npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
179
- pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
180
- return_char_limit: Optional[int] | Omit = omit,
181
- source_code: Optional[str] | Omit = omit,
182
- source_type: Optional[str] | Omit = omit,
183
- tags: Optional[SequenceNotStr[str]] | Omit = omit,
184
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
185
- # The extra values given here take precedence over values defined on the client or passed to this method.
186
- extra_headers: Headers | None = None,
187
- extra_query: Query | None = None,
188
- extra_body: Body | None = None,
189
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
190
- ) -> Tool:
191
- """
192
- Update an existing tool
193
-
194
- Args:
195
- tool_id: The ID of the tool in the format 'tool-<uuid4>'
196
-
197
- args_json_schema: The args JSON schema of the function.
198
-
199
- default_requires_approval: Whether or not to require approval before executing this tool.
200
-
201
- description: The description of the tool.
202
-
203
- enable_parallel_execution: If set to True, then this tool will potentially be executed concurrently with
204
- other tools. Default False.
205
-
206
- json_schema: The JSON schema of the function (auto-generated from source_code if not
207
- provided)
208
-
209
- metadata: A dictionary of additional metadata for the tool.
210
-
211
- npm_requirements: Optional list of npm packages required by this tool.
212
-
213
- pip_requirements: Optional list of pip packages required by this tool.
214
-
215
- return_char_limit: The maximum number of characters in the response.
216
-
217
- source_code: The source code of the function.
218
-
219
- source_type: The type of the source code.
220
-
221
- tags: Metadata tags.
222
-
223
- extra_headers: Send extra headers
224
-
225
- extra_query: Add additional query parameters to the request
226
-
227
- extra_body: Add additional JSON properties to the request
228
-
229
- timeout: Override the client-level default timeout for this request, in seconds
230
- """
231
- if not tool_id:
232
- raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
233
- return self._patch(
234
- f"/v1/tools/{tool_id}",
235
- body=maybe_transform(
236
- {
237
- "args_json_schema": args_json_schema,
238
- "default_requires_approval": default_requires_approval,
239
- "description": description,
240
- "enable_parallel_execution": enable_parallel_execution,
241
- "json_schema": json_schema,
242
- "metadata": metadata,
243
- "npm_requirements": npm_requirements,
244
- "pip_requirements": pip_requirements,
245
- "return_char_limit": return_char_limit,
246
- "source_code": source_code,
247
- "source_type": source_type,
248
- "tags": tags,
249
- },
250
- tool_update_params.ToolUpdateParams,
251
- ),
252
- options=make_request_options(
253
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
254
- ),
255
- cast_to=Tool,
256
- )
257
-
258
172
  def list(
259
173
  self,
260
174
  *,
@@ -276,7 +190,7 @@ class ToolsResource(SyncAPIResource):
276
190
  extra_query: Query | None = None,
277
191
  extra_body: Body | None = None,
278
192
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
279
- ) -> SyncArrayPage[Tool]:
193
+ ) -> ToolListResponse:
280
194
  """
281
195
  Get a list of all tools available to agents.
282
196
 
@@ -316,9 +230,8 @@ class ToolsResource(SyncAPIResource):
316
230
 
317
231
  timeout: Override the client-level default timeout for this request, in seconds
318
232
  """
319
- return self._get_api_list(
233
+ return self._get(
320
234
  "/v1/tools/",
321
- page=SyncArrayPage[Tool],
322
235
  options=make_request_options(
323
236
  extra_headers=extra_headers,
324
237
  extra_query=extra_query,
@@ -342,7 +255,7 @@ class ToolsResource(SyncAPIResource):
342
255
  tool_list_params.ToolListParams,
343
256
  ),
344
257
  ),
345
- model=Tool,
258
+ cast_to=ToolListResponse,
346
259
  )
347
260
 
348
261
  def delete(
@@ -448,19 +361,21 @@ class ToolsResource(SyncAPIResource):
448
361
  cast_to=int,
449
362
  )
450
363
 
451
- def upsert(
364
+ def modify(
452
365
  self,
366
+ tool_id: str,
453
367
  *,
454
- source_code: str,
455
368
  args_json_schema: Optional[Dict[str, object]] | Omit = omit,
456
369
  default_requires_approval: Optional[bool] | Omit = omit,
457
370
  description: Optional[str] | Omit = omit,
458
371
  enable_parallel_execution: Optional[bool] | Omit = omit,
459
372
  json_schema: Optional[Dict[str, object]] | Omit = omit,
373
+ metadata: Optional[Dict[str, object]] | Omit = omit,
460
374
  npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
461
375
  pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
462
- return_char_limit: int | Omit = omit,
463
- source_type: str | Omit = omit,
376
+ return_char_limit: Optional[int] | Omit = omit,
377
+ source_code: Optional[str] | Omit = omit,
378
+ source_type: Optional[str] | Omit = omit,
464
379
  tags: Optional[SequenceNotStr[str]] | Omit = omit,
465
380
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
466
381
  # The extra values given here take precedence over values defined on the client or passed to this method.
@@ -470,10 +385,10 @@ class ToolsResource(SyncAPIResource):
470
385
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
471
386
  ) -> Tool:
472
387
  """
473
- Create or update a tool
388
+ Update an existing tool
474
389
 
475
390
  Args:
476
- source_code: The source code of the function.
391
+ tool_id: The ID of the tool in the format 'tool-<uuid4>'
477
392
 
478
393
  args_json_schema: The args JSON schema of the function.
479
394
 
@@ -487,13 +402,17 @@ class ToolsResource(SyncAPIResource):
487
402
  json_schema: The JSON schema of the function (auto-generated from source_code if not
488
403
  provided)
489
404
 
405
+ metadata: A dictionary of additional metadata for the tool.
406
+
490
407
  npm_requirements: Optional list of npm packages required by this tool.
491
408
 
492
409
  pip_requirements: Optional list of pip packages required by this tool.
493
410
 
494
411
  return_char_limit: The maximum number of characters in the response.
495
412
 
496
- source_type: The source type of the function.
413
+ source_code: The source code of the function.
414
+
415
+ source_type: The type of the source code.
497
416
 
498
417
  tags: Metadata tags.
499
418
 
@@ -505,23 +424,26 @@ class ToolsResource(SyncAPIResource):
505
424
 
506
425
  timeout: Override the client-level default timeout for this request, in seconds
507
426
  """
508
- return self._put(
509
- "/v1/tools/",
427
+ if not tool_id:
428
+ raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
429
+ return self._patch(
430
+ f"/v1/tools/{tool_id}",
510
431
  body=maybe_transform(
511
432
  {
512
- "source_code": source_code,
513
433
  "args_json_schema": args_json_schema,
514
434
  "default_requires_approval": default_requires_approval,
515
435
  "description": description,
516
436
  "enable_parallel_execution": enable_parallel_execution,
517
437
  "json_schema": json_schema,
438
+ "metadata": metadata,
518
439
  "npm_requirements": npm_requirements,
519
440
  "pip_requirements": pip_requirements,
520
441
  "return_char_limit": return_char_limit,
442
+ "source_code": source_code,
521
443
  "source_type": source_type,
522
444
  "tags": tags,
523
445
  },
524
- tool_upsert_params.ToolUpsertParams,
446
+ tool_modify_params.ToolModifyParams,
525
447
  ),
526
448
  options=make_request_options(
527
449
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
@@ -529,47 +451,7 @@ class ToolsResource(SyncAPIResource):
529
451
  cast_to=Tool,
530
452
  )
531
453
 
532
- def upsert_base_tools(
533
- self,
534
- *,
535
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
536
- # The extra values given here take precedence over values defined on the client or passed to this method.
537
- extra_headers: Headers | None = None,
538
- extra_query: Query | None = None,
539
- extra_body: Body | None = None,
540
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
541
- ) -> ToolUpsertBaseToolsResponse:
542
- """Upsert base tools"""
543
- return self._post(
544
- "/v1/tools/add-base-tools",
545
- options=make_request_options(
546
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
547
- ),
548
- cast_to=ToolUpsertBaseToolsResponse,
549
- )
550
-
551
-
552
- class AsyncToolsResource(AsyncAPIResource):
553
- @cached_property
554
- def with_raw_response(self) -> AsyncToolsResourceWithRawResponse:
555
- """
556
- This property can be used as a prefix for any HTTP method call to return
557
- the raw response object instead of the parsed content.
558
-
559
- For more information, see https://www.github.com/letta-ai/letta-python#accessing-raw-response-data-eg-headers
560
- """
561
- return AsyncToolsResourceWithRawResponse(self)
562
-
563
- @cached_property
564
- def with_streaming_response(self) -> AsyncToolsResourceWithStreamingResponse:
565
- """
566
- An alternative to `.with_raw_response` that doesn't eagerly read the response body.
567
-
568
- For more information, see https://www.github.com/letta-ai/letta-python#with_streaming_response
569
- """
570
- return AsyncToolsResourceWithStreamingResponse(self)
571
-
572
- async def create(
454
+ def upsert(
573
455
  self,
574
456
  *,
575
457
  source_code: str,
@@ -591,7 +473,7 @@ class AsyncToolsResource(AsyncAPIResource):
591
473
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
592
474
  ) -> Tool:
593
475
  """
594
- Create a new tool
476
+ Create or update a tool
595
477
 
596
478
  Args:
597
479
  source_code: The source code of the function.
@@ -626,9 +508,9 @@ class AsyncToolsResource(AsyncAPIResource):
626
508
 
627
509
  timeout: Override the client-level default timeout for this request, in seconds
628
510
  """
629
- return await self._post(
511
+ return self._put(
630
512
  "/v1/tools/",
631
- body=await async_maybe_transform(
513
+ body=maybe_transform(
632
514
  {
633
515
  "source_code": source_code,
634
516
  "args_json_schema": args_json_schema,
@@ -642,7 +524,7 @@ class AsyncToolsResource(AsyncAPIResource):
642
524
  "source_type": source_type,
643
525
  "tags": tags,
644
526
  },
645
- tool_create_params.ToolCreateParams,
527
+ tool_upsert_params.ToolUpsertParams,
646
528
  ),
647
529
  options=make_request_options(
648
530
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
@@ -650,10 +532,139 @@ class AsyncToolsResource(AsyncAPIResource):
650
532
  cast_to=Tool,
651
533
  )
652
534
 
653
- async def retrieve(
535
+ def upsert_base_tools(
536
+ self,
537
+ *,
538
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
539
+ # The extra values given here take precedence over values defined on the client or passed to this method.
540
+ extra_headers: Headers | None = None,
541
+ extra_query: Query | None = None,
542
+ extra_body: Body | None = None,
543
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
544
+ ) -> ToolUpsertBaseToolsResponse:
545
+ """Upsert base tools"""
546
+ return self._post(
547
+ "/v1/tools/add-base-tools",
548
+ options=make_request_options(
549
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
550
+ ),
551
+ cast_to=ToolUpsertBaseToolsResponse,
552
+ )
553
+
554
+ def create_from_function(
555
+ self,
556
+ *,
557
+ func: typing.Callable[..., typing.Any],
558
+ args_schema: typing.Optional[typing.Type[BaseModel]] | Omit = omit,
559
+ description: Optional[str] | Omit = omit,
560
+ tags: Optional[SequenceNotStr[str]] | Omit = omit,
561
+ source_type: str | Omit = omit,
562
+ json_schema: Optional[Dict[str, object]] | Omit = omit,
563
+ return_char_limit: int | Omit = omit,
564
+ pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
565
+ npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
566
+ default_requires_approval: Optional[bool] | Omit = omit,
567
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
568
+ # The extra values given here take precedence over values defined on the client or passed to this method.
569
+ extra_headers: Headers | None = None,
570
+ extra_query: Query | None = None,
571
+ extra_body: Body | None = None,
572
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
573
+ ) -> Tool:
574
+ """
575
+ Create a new tool from a callable
576
+
577
+ Args:
578
+ func: The callable to create the tool from.
579
+
580
+ args_schema: The arguments schema of the function, as a Pydantic model.
581
+
582
+ description: The description of the tool.
583
+
584
+ tags: Metadata tags.
585
+
586
+ source_type: The source type of the function.
587
+
588
+ json_schema: The JSON schema of the function (auto-generated from source_code if not
589
+ provided)
590
+
591
+ return_char_limit: The maximum number of characters in the response.
592
+
593
+ pip_requirements: Optional list of pip packages required by this tool.
594
+
595
+ npm_requirements: Optional list of npm packages required by this tool.
596
+
597
+ default_requires_approval: Whether or not to require approval before executing this tool.
598
+
599
+ extra_headers: Send extra headers
600
+
601
+ extra_query: Add additional query parameters to the request
602
+
603
+ extra_body: Add additional JSON properties to the request
604
+
605
+ timeout: Override the client-level default timeout for this request, in seconds
606
+
607
+ Examples:
608
+ from letta_client import Letta
609
+
610
+ client = Letta(
611
+ token="YOUR_TOKEN",
612
+ )
613
+
614
+ def add_two_numbers(a: int, b: int) -> int:
615
+ return a + b
616
+
617
+ client.tools.create_from_function(
618
+ func=add_two_numbers,
619
+ )
620
+
621
+ class InventoryEntryData(BaseModel):
622
+ data: InventoryEntry
623
+ quantity_change: int
624
+
625
+ def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
626
+ pass
627
+
628
+ client.tools.create_from_function(
629
+ func=manage_inventory,
630
+ args_schema=InventoryEntryData,
631
+ )
632
+ """
633
+ source_code = dedent(inspect.getsource(func))
634
+ args_json_schema: Optional[Dict[str, object]] | Omit = omit
635
+ if not isinstance(args_schema, Omit) and args_schema is not None:
636
+ args_json_schema = args_schema.model_json_schema()
637
+
638
+ return self.create(
639
+ source_code=source_code,
640
+ args_json_schema=args_json_schema,
641
+ description=description,
642
+ tags=tags,
643
+ source_type=source_type,
644
+ json_schema=json_schema,
645
+ return_char_limit=return_char_limit,
646
+ pip_requirements=pip_requirements,
647
+ npm_requirements=npm_requirements,
648
+ default_requires_approval=default_requires_approval,
649
+ extra_headers=extra_headers,
650
+ extra_query=extra_query,
651
+ extra_body=extra_body,
652
+ timeout=timeout,
653
+ )
654
+
655
+ def upsert_from_function(
654
656
  self,
655
- tool_id: str,
656
657
  *,
658
+ func: typing.Callable[..., typing.Any],
659
+ args_schema: typing.Optional[typing.Type[BaseModel]] | Omit = omit,
660
+ description: Optional[str] | Omit = omit,
661
+ tags: Optional[SequenceNotStr[str]] | Omit = omit,
662
+ source_type: str | Omit = omit,
663
+ json_schema: Optional[Dict[str, object]] | Omit = omit,
664
+ return_char_limit: int | Omit = omit,
665
+ pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
666
+ npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
667
+ default_requires_approval: Optional[bool] | Omit = omit,
657
668
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
658
669
  # The extra values given here take precedence over values defined on the client or passed to this method.
659
670
  extra_headers: Headers | None = None,
@@ -662,10 +673,29 @@ class AsyncToolsResource(AsyncAPIResource):
662
673
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
663
674
  ) -> Tool:
664
675
  """
665
- Get a tool by ID
676
+ Create or update a tool from a callable
666
677
 
667
678
  Args:
668
- tool_id: The ID of the tool in the format 'tool-<uuid4>'
679
+ func: The callable to create or update the tool from.
680
+
681
+ args_schema: The arguments schema of the function, as a Pydantic model.
682
+
683
+ description: The description of the tool.
684
+
685
+ tags: Metadata tags.
686
+
687
+ source_type: The source type of the function.
688
+
689
+ json_schema: The JSON schema of the function (auto-generated from source_code if not
690
+ provided)
691
+
692
+ return_char_limit: The maximum number of characters in the response.
693
+
694
+ pip_requirements: Optional list of pip packages required by this tool.
695
+
696
+ npm_requirements: Optional list of npm packages required by this tool.
697
+
698
+ default_requires_approval: Whether or not to require approval before executing this tool.
669
699
 
670
700
  extra_headers: Send extra headers
671
701
 
@@ -674,32 +704,184 @@ class AsyncToolsResource(AsyncAPIResource):
674
704
  extra_body: Add additional JSON properties to the request
675
705
 
676
706
  timeout: Override the client-level default timeout for this request, in seconds
707
+
708
+ Examples:
709
+ from letta_client import Letta
710
+
711
+ client = Letta(
712
+ token="YOUR_TOKEN",
713
+ )
714
+
715
+ def add_two_numbers(a: int, b: int) -> int:
716
+ return a + b
717
+
718
+ client.tools.upsert_from_function(
719
+ func=add_two_numbers,
720
+ )
721
+
722
+ class InventoryEntryData(BaseModel):
723
+ data: InventoryEntry
724
+ quantity_change: int
725
+
726
+ def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
727
+ pass
728
+
729
+ client.tools.upsert_from_function(
730
+ func=manage_inventory,
731
+ args_schema=InventoryEntryData,
732
+ )
677
733
  """
678
- if not tool_id:
679
- raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
680
- return await self._get(
681
- f"/v1/tools/{tool_id}",
682
- options=make_request_options(
683
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
684
- ),
685
- cast_to=Tool,
734
+ source_code = dedent(inspect.getsource(func))
735
+ args_json_schema: Optional[Dict[str, object]] | Omit = omit
736
+ if not isinstance(args_schema, Omit) and args_schema is not None:
737
+ args_json_schema = args_schema.model_json_schema()
738
+
739
+ return self.upsert(
740
+ source_code=source_code,
741
+ args_json_schema=args_json_schema,
742
+ description=description,
743
+ tags=tags,
744
+ source_type=source_type,
745
+ json_schema=json_schema,
746
+ return_char_limit=return_char_limit,
747
+ pip_requirements=pip_requirements,
748
+ npm_requirements=npm_requirements,
749
+ default_requires_approval=default_requires_approval,
750
+ extra_headers=extra_headers,
751
+ extra_query=extra_query,
752
+ extra_body=extra_body,
753
+ timeout=timeout,
686
754
  )
687
755
 
688
- async def update(
756
+ def add(
757
+ self,
758
+ *,
759
+ tool: BaseTool,
760
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
761
+ # The extra values given here take precedence over values defined on the client or passed to this method.
762
+ extra_headers: Headers | None = None,
763
+ extra_query: Query | None = None,
764
+ extra_body: Body | None = None,
765
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
766
+ ) -> Tool:
767
+ """
768
+ Add a tool to Letta from a custom Tool class
769
+
770
+ Args:
771
+ tool: The tool object to be added.
772
+
773
+ extra_headers: Send extra headers
774
+
775
+ extra_query: Add additional query parameters to the request
776
+
777
+ extra_body: Add additional JSON properties to the request
778
+
779
+ timeout: Override the client-level default timeout for this request, in seconds
780
+
781
+ Examples:
782
+ from letta_client import Letta
783
+
784
+ client = Letta(
785
+ token="YOUR_TOKEN",
786
+ )
787
+
788
+ class InventoryItem(BaseModel):
789
+ sku: str # Unique product identifier
790
+ name: str # Product name
791
+ price: float # Current price
792
+ category: str # Product category (e.g., "Electronics", "Clothing")
793
+
794
+ class InventoryEntry(BaseModel):
795
+ timestamp: int # Unix timestamp of the transaction
796
+ item: InventoryItem # The product being updated
797
+ transaction_id: str # Unique identifier for this inventory update
798
+
799
+ class InventoryEntryData(BaseModel):
800
+ data: InventoryEntry
801
+ quantity_change: int # Change in quantity (positive for additions, negative for removals)
802
+
803
+ class ManageInventoryTool(BaseTool):
804
+ name: str = "manage_inventory"
805
+ args_schema: Type[BaseModel] = InventoryEntryData
806
+ description: str = "Update inventory catalogue with a new data entry"
807
+ tags: List[str] = ["inventory", "shop"]
808
+
809
+ def run(self, data: InventoryEntry, quantity_change: int) -> bool:
810
+ '''
811
+ Implementation of the manage_inventory tool
812
+ '''
813
+ print(f"Updated inventory for {data.item.name} with a quantity change of {quantity_change}")
814
+ return True
815
+
816
+ client.tools.add(
817
+ tool=ManageInventoryTool()
818
+ )
819
+ """
820
+ source_code = tool.get_source_code()
821
+ args_json_schema = tool.args_schema.model_json_schema() if tool.args_schema else None
822
+
823
+ # Convert PipRequirement/NpmRequirement models to Param dicts
824
+ pip_requirements_param = (
825
+ [typing.cast(PipRequirementParam, req.model_dump()) for req in tool.pip_requirements]
826
+ if tool.pip_requirements
827
+ else omit
828
+ )
829
+ npm_requirements_param = (
830
+ [typing.cast(NpmRequirementParam, req.model_dump()) for req in tool.npm_requirements]
831
+ if tool.npm_requirements
832
+ else omit
833
+ )
834
+
835
+ return self.upsert(
836
+ source_code=source_code,
837
+ args_json_schema=args_json_schema or omit,
838
+ description=tool.description or omit,
839
+ tags=tool.tags or omit,
840
+ source_type=tool.source_type or omit,
841
+ json_schema=tool.json_schema or omit,
842
+ return_char_limit=tool.return_char_limit or omit,
843
+ pip_requirements=pip_requirements_param,
844
+ npm_requirements=npm_requirements_param,
845
+ default_requires_approval=tool.default_requires_approval or omit,
846
+ extra_headers=extra_headers,
847
+ extra_query=extra_query,
848
+ extra_body=extra_body,
849
+ timeout=timeout,
850
+ )
851
+
852
+ class AsyncToolsResource(AsyncAPIResource):
853
+ @cached_property
854
+ def with_raw_response(self) -> AsyncToolsResourceWithRawResponse:
855
+ """
856
+ This property can be used as a prefix for any HTTP method call to return
857
+ the raw response object instead of the parsed content.
858
+
859
+ For more information, see https://www.github.com/letta-ai/letta-python#accessing-raw-response-data-eg-headers
860
+ """
861
+ return AsyncToolsResourceWithRawResponse(self)
862
+
863
+ @cached_property
864
+ def with_streaming_response(self) -> AsyncToolsResourceWithStreamingResponse:
865
+ """
866
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
867
+
868
+ For more information, see https://www.github.com/letta-ai/letta-python#with_streaming_response
869
+ """
870
+ return AsyncToolsResourceWithStreamingResponse(self)
871
+
872
+ async def create(
689
873
  self,
690
- tool_id: str,
691
874
  *,
875
+ source_code: str,
692
876
  args_json_schema: Optional[Dict[str, object]] | Omit = omit,
693
877
  default_requires_approval: Optional[bool] | Omit = omit,
694
878
  description: Optional[str] | Omit = omit,
695
879
  enable_parallel_execution: Optional[bool] | Omit = omit,
696
880
  json_schema: Optional[Dict[str, object]] | Omit = omit,
697
- metadata: Optional[Dict[str, object]] | Omit = omit,
698
881
  npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
699
882
  pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
700
- return_char_limit: Optional[int] | Omit = omit,
701
- source_code: Optional[str] | Omit = omit,
702
- source_type: Optional[str] | Omit = omit,
883
+ return_char_limit: int | Omit = omit,
884
+ source_type: str | Omit = omit,
703
885
  tags: Optional[SequenceNotStr[str]] | Omit = omit,
704
886
  # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
705
887
  # The extra values given here take precedence over values defined on the client or passed to this method.
@@ -709,10 +891,10 @@ class AsyncToolsResource(AsyncAPIResource):
709
891
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
710
892
  ) -> Tool:
711
893
  """
712
- Update an existing tool
894
+ Create a new tool
713
895
 
714
896
  Args:
715
- tool_id: The ID of the tool in the format 'tool-<uuid4>'
897
+ source_code: The source code of the function.
716
898
 
717
899
  args_json_schema: The args JSON schema of the function.
718
900
 
@@ -726,17 +908,13 @@ class AsyncToolsResource(AsyncAPIResource):
726
908
  json_schema: The JSON schema of the function (auto-generated from source_code if not
727
909
  provided)
728
910
 
729
- metadata: A dictionary of additional metadata for the tool.
730
-
731
911
  npm_requirements: Optional list of npm packages required by this tool.
732
912
 
733
913
  pip_requirements: Optional list of pip packages required by this tool.
734
914
 
735
915
  return_char_limit: The maximum number of characters in the response.
736
916
 
737
- source_code: The source code of the function.
738
-
739
- source_type: The type of the source code.
917
+ source_type: The source type of the function.
740
918
 
741
919
  tags: Metadata tags.
742
920
 
@@ -748,34 +926,66 @@ class AsyncToolsResource(AsyncAPIResource):
748
926
 
749
927
  timeout: Override the client-level default timeout for this request, in seconds
750
928
  """
751
- if not tool_id:
752
- raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
753
- return await self._patch(
754
- f"/v1/tools/{tool_id}",
929
+ return await self._post(
930
+ "/v1/tools/",
755
931
  body=await async_maybe_transform(
756
932
  {
933
+ "source_code": source_code,
757
934
  "args_json_schema": args_json_schema,
758
935
  "default_requires_approval": default_requires_approval,
759
936
  "description": description,
760
937
  "enable_parallel_execution": enable_parallel_execution,
761
938
  "json_schema": json_schema,
762
- "metadata": metadata,
763
939
  "npm_requirements": npm_requirements,
764
940
  "pip_requirements": pip_requirements,
765
941
  "return_char_limit": return_char_limit,
766
- "source_code": source_code,
767
942
  "source_type": source_type,
768
943
  "tags": tags,
769
944
  },
770
- tool_update_params.ToolUpdateParams,
945
+ tool_create_params.ToolCreateParams,
946
+ ),
947
+ options=make_request_options(
948
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
771
949
  ),
950
+ cast_to=Tool,
951
+ )
952
+
953
+ async def retrieve(
954
+ self,
955
+ tool_id: str,
956
+ *,
957
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
958
+ # The extra values given here take precedence over values defined on the client or passed to this method.
959
+ extra_headers: Headers | None = None,
960
+ extra_query: Query | None = None,
961
+ extra_body: Body | None = None,
962
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
963
+ ) -> Tool:
964
+ """
965
+ Get a tool by ID
966
+
967
+ Args:
968
+ tool_id: The ID of the tool in the format 'tool-<uuid4>'
969
+
970
+ extra_headers: Send extra headers
971
+
972
+ extra_query: Add additional query parameters to the request
973
+
974
+ extra_body: Add additional JSON properties to the request
975
+
976
+ timeout: Override the client-level default timeout for this request, in seconds
977
+ """
978
+ if not tool_id:
979
+ raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
980
+ return await self._get(
981
+ f"/v1/tools/{tool_id}",
772
982
  options=make_request_options(
773
983
  extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
774
984
  ),
775
985
  cast_to=Tool,
776
986
  )
777
987
 
778
- def list(
988
+ async def list(
779
989
  self,
780
990
  *,
781
991
  after: Optional[str] | Omit = omit,
@@ -796,7 +1006,7 @@ class AsyncToolsResource(AsyncAPIResource):
796
1006
  extra_query: Query | None = None,
797
1007
  extra_body: Body | None = None,
798
1008
  timeout: float | httpx.Timeout | None | NotGiven = not_given,
799
- ) -> AsyncPaginator[Tool, AsyncArrayPage[Tool]]:
1009
+ ) -> ToolListResponse:
800
1010
  """
801
1011
  Get a list of all tools available to agents.
802
1012
 
@@ -836,15 +1046,14 @@ class AsyncToolsResource(AsyncAPIResource):
836
1046
 
837
1047
  timeout: Override the client-level default timeout for this request, in seconds
838
1048
  """
839
- return self._get_api_list(
1049
+ return await self._get(
840
1050
  "/v1/tools/",
841
- page=AsyncArrayPage[Tool],
842
1051
  options=make_request_options(
843
1052
  extra_headers=extra_headers,
844
1053
  extra_query=extra_query,
845
1054
  extra_body=extra_body,
846
1055
  timeout=timeout,
847
- query=maybe_transform(
1056
+ query=await async_maybe_transform(
848
1057
  {
849
1058
  "after": after,
850
1059
  "before": before,
@@ -862,7 +1071,7 @@ class AsyncToolsResource(AsyncAPIResource):
862
1071
  tool_list_params.ToolListParams,
863
1072
  ),
864
1073
  ),
865
- model=Tool,
1074
+ cast_to=ToolListResponse,
866
1075
  )
867
1076
 
868
1077
  async def delete(
@@ -968,6 +1177,96 @@ class AsyncToolsResource(AsyncAPIResource):
968
1177
  cast_to=int,
969
1178
  )
970
1179
 
1180
+ async def modify(
1181
+ self,
1182
+ tool_id: str,
1183
+ *,
1184
+ args_json_schema: Optional[Dict[str, object]] | Omit = omit,
1185
+ default_requires_approval: Optional[bool] | Omit = omit,
1186
+ description: Optional[str] | Omit = omit,
1187
+ enable_parallel_execution: Optional[bool] | Omit = omit,
1188
+ json_schema: Optional[Dict[str, object]] | Omit = omit,
1189
+ metadata: Optional[Dict[str, object]] | Omit = omit,
1190
+ npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
1191
+ pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
1192
+ return_char_limit: Optional[int] | Omit = omit,
1193
+ source_code: Optional[str] | Omit = omit,
1194
+ source_type: Optional[str] | Omit = omit,
1195
+ tags: Optional[SequenceNotStr[str]] | Omit = omit,
1196
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1197
+ # The extra values given here take precedence over values defined on the client or passed to this method.
1198
+ extra_headers: Headers | None = None,
1199
+ extra_query: Query | None = None,
1200
+ extra_body: Body | None = None,
1201
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1202
+ ) -> Tool:
1203
+ """
1204
+ Update an existing tool
1205
+
1206
+ Args:
1207
+ tool_id: The ID of the tool in the format 'tool-<uuid4>'
1208
+
1209
+ args_json_schema: The args JSON schema of the function.
1210
+
1211
+ default_requires_approval: Whether or not to require approval before executing this tool.
1212
+
1213
+ description: The description of the tool.
1214
+
1215
+ enable_parallel_execution: If set to True, then this tool will potentially be executed concurrently with
1216
+ other tools. Default False.
1217
+
1218
+ json_schema: The JSON schema of the function (auto-generated from source_code if not
1219
+ provided)
1220
+
1221
+ metadata: A dictionary of additional metadata for the tool.
1222
+
1223
+ npm_requirements: Optional list of npm packages required by this tool.
1224
+
1225
+ pip_requirements: Optional list of pip packages required by this tool.
1226
+
1227
+ return_char_limit: The maximum number of characters in the response.
1228
+
1229
+ source_code: The source code of the function.
1230
+
1231
+ source_type: The type of the source code.
1232
+
1233
+ tags: Metadata tags.
1234
+
1235
+ extra_headers: Send extra headers
1236
+
1237
+ extra_query: Add additional query parameters to the request
1238
+
1239
+ extra_body: Add additional JSON properties to the request
1240
+
1241
+ timeout: Override the client-level default timeout for this request, in seconds
1242
+ """
1243
+ if not tool_id:
1244
+ raise ValueError(f"Expected a non-empty value for `tool_id` but received {tool_id!r}")
1245
+ return await self._patch(
1246
+ f"/v1/tools/{tool_id}",
1247
+ body=await async_maybe_transform(
1248
+ {
1249
+ "args_json_schema": args_json_schema,
1250
+ "default_requires_approval": default_requires_approval,
1251
+ "description": description,
1252
+ "enable_parallel_execution": enable_parallel_execution,
1253
+ "json_schema": json_schema,
1254
+ "metadata": metadata,
1255
+ "npm_requirements": npm_requirements,
1256
+ "pip_requirements": pip_requirements,
1257
+ "return_char_limit": return_char_limit,
1258
+ "source_code": source_code,
1259
+ "source_type": source_type,
1260
+ "tags": tags,
1261
+ },
1262
+ tool_modify_params.ToolModifyParams,
1263
+ ),
1264
+ options=make_request_options(
1265
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
1266
+ ),
1267
+ cast_to=Tool,
1268
+ )
1269
+
971
1270
  async def upsert(
972
1271
  self,
973
1272
  *,
@@ -1068,6 +1367,305 @@ class AsyncToolsResource(AsyncAPIResource):
1068
1367
  cast_to=ToolUpsertBaseToolsResponse,
1069
1368
  )
1070
1369
 
1370
+ async def create_from_function(
1371
+ self,
1372
+ *,
1373
+ func: typing.Callable[..., typing.Any],
1374
+ args_schema: typing.Optional[typing.Type[BaseModel]] | Omit = omit,
1375
+ description: Optional[str] | Omit = omit,
1376
+ tags: Optional[SequenceNotStr[str]] | Omit = omit,
1377
+ source_type: str | Omit = omit,
1378
+ json_schema: Optional[Dict[str, object]] | Omit = omit,
1379
+ return_char_limit: int | Omit = omit,
1380
+ pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
1381
+ npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
1382
+ default_requires_approval: Optional[bool] | Omit = omit,
1383
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1384
+ # The extra values given here take precedence over values defined on the client or passed to this method.
1385
+ extra_headers: Headers | None = None,
1386
+ extra_query: Query | None = None,
1387
+ extra_body: Body | None = None,
1388
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1389
+ ) -> Tool:
1390
+ """
1391
+ Create a new tool from a callable
1392
+
1393
+ Args:
1394
+ func: The callable to create the tool from.
1395
+
1396
+ args_schema: The arguments schema of the function, as a Pydantic model.
1397
+
1398
+ description: The description of the tool.
1399
+
1400
+ tags: Metadata tags.
1401
+
1402
+ source_type: The source type of the function.
1403
+
1404
+ json_schema: The JSON schema of the function (auto-generated from source_code if not
1405
+ provided)
1406
+
1407
+ return_char_limit: The maximum number of characters in the response.
1408
+
1409
+ pip_requirements: Optional list of pip packages required by this tool.
1410
+
1411
+ npm_requirements: Optional list of npm packages required by this tool.
1412
+
1413
+ default_requires_approval: Whether or not to require approval before executing this tool.
1414
+
1415
+ extra_headers: Send extra headers
1416
+
1417
+ extra_query: Add additional query parameters to the request
1418
+
1419
+ extra_body: Add additional JSON properties to the request
1420
+
1421
+ timeout: Override the client-level default timeout for this request, in seconds
1422
+
1423
+ Examples:
1424
+ from letta_client import Letta
1425
+
1426
+ client = Letta(
1427
+ token="YOUR_TOKEN",
1428
+ )
1429
+
1430
+ def add_two_numbers(a: int, b: int) -> int:
1431
+ return a + b
1432
+
1433
+ await client.tools.create_from_function(
1434
+ func=add_two_numbers,
1435
+ )
1436
+
1437
+ class InventoryEntryData(BaseModel):
1438
+ data: InventoryEntry
1439
+ quantity_change: int
1440
+
1441
+ def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
1442
+ pass
1443
+
1444
+ await client.tools.create_from_function(
1445
+ func=manage_inventory,
1446
+ args_schema=InventoryEntryData,
1447
+ )
1448
+ """
1449
+ source_code = dedent(inspect.getsource(func))
1450
+ args_json_schema: Optional[Dict[str, object]] | Omit = omit
1451
+ if not isinstance(args_schema, Omit) and args_schema is not None:
1452
+ args_json_schema = args_schema.model_json_schema()
1453
+
1454
+ return await self.create(
1455
+ source_code=source_code,
1456
+ args_json_schema=args_json_schema,
1457
+ description=description,
1458
+ tags=tags,
1459
+ source_type=source_type,
1460
+ json_schema=json_schema,
1461
+ return_char_limit=return_char_limit,
1462
+ pip_requirements=pip_requirements,
1463
+ npm_requirements=npm_requirements,
1464
+ default_requires_approval=default_requires_approval,
1465
+ extra_headers=extra_headers,
1466
+ extra_query=extra_query,
1467
+ extra_body=extra_body,
1468
+ timeout=timeout,
1469
+ )
1470
+
1471
+
1472
+ async def upsert_from_function(
1473
+ self,
1474
+ *,
1475
+ func: typing.Callable[..., typing.Any],
1476
+ args_schema: typing.Optional[typing.Type[BaseModel]] | Omit = omit,
1477
+ description: Optional[str] | Omit = omit,
1478
+ tags: Optional[SequenceNotStr[str]] | Omit = omit,
1479
+ source_type: str | Omit = omit,
1480
+ json_schema: Optional[Dict[str, object]] | Omit = omit,
1481
+ return_char_limit: int | Omit = omit,
1482
+ pip_requirements: Optional[Iterable[PipRequirementParam]] | Omit = omit,
1483
+ npm_requirements: Optional[Iterable[NpmRequirementParam]] | Omit = omit,
1484
+ default_requires_approval: Optional[bool] | Omit = omit,
1485
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1486
+ # The extra values given here take precedence over values defined on the client or passed to this method.
1487
+ extra_headers: Headers | None = None,
1488
+ extra_query: Query | None = None,
1489
+ extra_body: Body | None = None,
1490
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1491
+ ) -> Tool:
1492
+ """
1493
+ Create or update a tool from a callable
1494
+
1495
+ Args:
1496
+ func: The callable to create or update the tool from.
1497
+
1498
+ args_schema: The arguments schema of the function, as a Pydantic model.
1499
+
1500
+ description: The description of the tool.
1501
+
1502
+ tags: Metadata tags.
1503
+
1504
+ source_type: The source type of the function.
1505
+
1506
+ json_schema: The JSON schema of the function (auto-generated from source_code if not
1507
+ provided)
1508
+
1509
+ return_char_limit: The maximum number of characters in the response.
1510
+
1511
+ pip_requirements: Optional list of pip packages required by this tool.
1512
+
1513
+ npm_requirements: Optional list of npm packages required by this tool.
1514
+
1515
+ default_requires_approval: Whether or not to require approval before executing this tool.
1516
+
1517
+ extra_headers: Send extra headers
1518
+
1519
+ extra_query: Add additional query parameters to the request
1520
+
1521
+ extra_body: Add additional JSON properties to the request
1522
+
1523
+ timeout: Override the client-level default timeout for this request, in seconds
1524
+
1525
+ Examples:
1526
+ from letta_client import Letta
1527
+
1528
+ client = Letta(
1529
+ token="YOUR_TOKEN",
1530
+ )
1531
+
1532
+ def add_two_numbers(a: int, b: int) -> int:
1533
+ return a + b
1534
+
1535
+ await client.tools.upsert_from_function(
1536
+ func=add_two_numbers,
1537
+ )
1538
+
1539
+ class InventoryEntryData(BaseModel):
1540
+ data: InventoryEntry
1541
+ quantity_change: int
1542
+
1543
+ def manage_inventory(data: InventoryEntry, quantity_change: int) -> bool:
1544
+ pass
1545
+
1546
+ await client.tools.upsert_from_function(
1547
+ func=manage_inventory,
1548
+ args_schema=InventoryEntryData,
1549
+ )
1550
+ """
1551
+ source_code = dedent(inspect.getsource(func))
1552
+ args_json_schema: Optional[Dict[str, object]] | Omit = omit
1553
+ if not isinstance(args_schema, Omit) and args_schema is not None:
1554
+ args_json_schema = args_schema.model_json_schema()
1555
+
1556
+ return await self.upsert(
1557
+ source_code=source_code,
1558
+ args_json_schema=args_json_schema,
1559
+ description=description,
1560
+ tags=tags,
1561
+ source_type=source_type,
1562
+ json_schema=json_schema,
1563
+ return_char_limit=return_char_limit,
1564
+ pip_requirements=pip_requirements,
1565
+ npm_requirements=npm_requirements,
1566
+ default_requires_approval=default_requires_approval,
1567
+ extra_headers=extra_headers,
1568
+ extra_query=extra_query,
1569
+ extra_body=extra_body,
1570
+ timeout=timeout,
1571
+ )
1572
+
1573
+ async def add(
1574
+ self,
1575
+ *,
1576
+ tool: BaseTool,
1577
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
1578
+ # The extra values given here take precedence over values defined on the client or passed to this method.
1579
+ extra_headers: Headers | None = None,
1580
+ extra_query: Query | None = None,
1581
+ extra_body: Body | None = None,
1582
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
1583
+ ) -> Tool:
1584
+ """
1585
+ Add a tool to Letta from a custom Tool class
1586
+
1587
+ Args:
1588
+ tool: The tool object to be added.
1589
+
1590
+ extra_headers: Send extra headers
1591
+
1592
+ extra_query: Add additional query parameters to the request
1593
+
1594
+ extra_body: Add additional JSON properties to the request
1595
+
1596
+ timeout: Override the client-level default timeout for this request, in seconds
1597
+
1598
+ Examples:
1599
+ from letta_client import Letta
1600
+
1601
+ client = Letta(
1602
+ token="YOUR_TOKEN",
1603
+ )
1604
+
1605
+ class InventoryItem(BaseModel):
1606
+ sku: str # Unique product identifier
1607
+ name: str # Product name
1608
+ price: float # Current price
1609
+ category: str # Product category (e.g., "Electronics", "Clothing")
1610
+
1611
+ class InventoryEntry(BaseModel):
1612
+ timestamp: int # Unix timestamp of the transaction
1613
+ item: InventoryItem # The product being updated
1614
+ transaction_id: str # Unique identifier for this inventory update
1615
+
1616
+ class InventoryEntryData(BaseModel):
1617
+ data: InventoryEntry
1618
+ quantity_change: int # Change in quantity (positive for additions, negative for removals)
1619
+
1620
+ class ManageInventoryTool(BaseTool):
1621
+ name: str = "manage_inventory"
1622
+ args_schema: Type[BaseModel] = InventoryEntryData
1623
+ description: str = "Update inventory catalogue with a new data entry"
1624
+ tags: List[str] = ["inventory", "shop"]
1625
+
1626
+ def run(self, data: InventoryEntry, quantity_change: int) -> bool:
1627
+ '''
1628
+ Implementation of the manage_inventory tool
1629
+ '''
1630
+ print(f"Updated inventory for {data.item.name} with a quantity change of {quantity_change}")
1631
+ return True
1632
+
1633
+ await client.tools.add(
1634
+ tool=ManageInventoryTool()
1635
+ )
1636
+ """
1637
+ source_code = tool.get_source_code()
1638
+ args_json_schema = tool.args_schema.model_json_schema() if tool.args_schema else None
1639
+
1640
+ # Convert PipRequirement/NpmRequirement models to Param dicts
1641
+ pip_requirements_param = (
1642
+ [typing.cast(PipRequirementParam, req.model_dump()) for req in tool.pip_requirements]
1643
+ if tool.pip_requirements
1644
+ else omit
1645
+ )
1646
+ npm_requirements_param = (
1647
+ [typing.cast(NpmRequirementParam, req.model_dump()) for req in tool.npm_requirements]
1648
+ if tool.npm_requirements
1649
+ else omit
1650
+ )
1651
+
1652
+ return await self.upsert(
1653
+ source_code=source_code,
1654
+ args_json_schema=args_json_schema or omit,
1655
+ description=tool.description or omit,
1656
+ tags=tool.tags or omit,
1657
+ source_type=tool.source_type or omit,
1658
+ json_schema=tool.json_schema or omit,
1659
+ return_char_limit=tool.return_char_limit or omit,
1660
+ pip_requirements=pip_requirements_param,
1661
+ npm_requirements=npm_requirements_param,
1662
+ default_requires_approval=tool.default_requires_approval or omit,
1663
+ extra_headers=extra_headers,
1664
+ extra_query=extra_query,
1665
+ extra_body=extra_body,
1666
+ timeout=timeout,
1667
+ )
1668
+
1071
1669
 
1072
1670
  class ToolsResourceWithRawResponse:
1073
1671
  def __init__(self, tools: ToolsResource) -> None:
@@ -1079,9 +1677,6 @@ class ToolsResourceWithRawResponse:
1079
1677
  self.retrieve = to_raw_response_wrapper(
1080
1678
  tools.retrieve,
1081
1679
  )
1082
- self.update = to_raw_response_wrapper(
1083
- tools.update,
1084
- )
1085
1680
  self.list = to_raw_response_wrapper(
1086
1681
  tools.list,
1087
1682
  )
@@ -1091,6 +1686,9 @@ class ToolsResourceWithRawResponse:
1091
1686
  self.count = to_raw_response_wrapper(
1092
1687
  tools.count,
1093
1688
  )
1689
+ self.modify = to_raw_response_wrapper(
1690
+ tools.modify,
1691
+ )
1094
1692
  self.upsert = to_raw_response_wrapper(
1095
1693
  tools.upsert,
1096
1694
  )
@@ -1109,9 +1707,6 @@ class AsyncToolsResourceWithRawResponse:
1109
1707
  self.retrieve = async_to_raw_response_wrapper(
1110
1708
  tools.retrieve,
1111
1709
  )
1112
- self.update = async_to_raw_response_wrapper(
1113
- tools.update,
1114
- )
1115
1710
  self.list = async_to_raw_response_wrapper(
1116
1711
  tools.list,
1117
1712
  )
@@ -1121,6 +1716,9 @@ class AsyncToolsResourceWithRawResponse:
1121
1716
  self.count = async_to_raw_response_wrapper(
1122
1717
  tools.count,
1123
1718
  )
1719
+ self.modify = async_to_raw_response_wrapper(
1720
+ tools.modify,
1721
+ )
1124
1722
  self.upsert = async_to_raw_response_wrapper(
1125
1723
  tools.upsert,
1126
1724
  )
@@ -1139,9 +1737,6 @@ class ToolsResourceWithStreamingResponse:
1139
1737
  self.retrieve = to_streamed_response_wrapper(
1140
1738
  tools.retrieve,
1141
1739
  )
1142
- self.update = to_streamed_response_wrapper(
1143
- tools.update,
1144
- )
1145
1740
  self.list = to_streamed_response_wrapper(
1146
1741
  tools.list,
1147
1742
  )
@@ -1151,6 +1746,9 @@ class ToolsResourceWithStreamingResponse:
1151
1746
  self.count = to_streamed_response_wrapper(
1152
1747
  tools.count,
1153
1748
  )
1749
+ self.modify = to_streamed_response_wrapper(
1750
+ tools.modify,
1751
+ )
1154
1752
  self.upsert = to_streamed_response_wrapper(
1155
1753
  tools.upsert,
1156
1754
  )
@@ -1169,9 +1767,6 @@ class AsyncToolsResourceWithStreamingResponse:
1169
1767
  self.retrieve = async_to_streamed_response_wrapper(
1170
1768
  tools.retrieve,
1171
1769
  )
1172
- self.update = async_to_streamed_response_wrapper(
1173
- tools.update,
1174
- )
1175
1770
  self.list = async_to_streamed_response_wrapper(
1176
1771
  tools.list,
1177
1772
  )
@@ -1181,6 +1776,9 @@ class AsyncToolsResourceWithStreamingResponse:
1181
1776
  self.count = async_to_streamed_response_wrapper(
1182
1777
  tools.count,
1183
1778
  )
1779
+ self.modify = async_to_streamed_response_wrapper(
1780
+ tools.modify,
1781
+ )
1184
1782
  self.upsert = async_to_streamed_response_wrapper(
1185
1783
  tools.upsert,
1186
1784
  )