letta-nightly 0.1.7.dev20240924104148__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-nightly might be problematic. Click here for more details.

Files changed (189) hide show
  1. letta/__init__.py +24 -0
  2. letta/__main__.py +3 -0
  3. letta/agent.py +1427 -0
  4. letta/agent_store/chroma.py +295 -0
  5. letta/agent_store/db.py +546 -0
  6. letta/agent_store/lancedb.py +177 -0
  7. letta/agent_store/milvus.py +198 -0
  8. letta/agent_store/qdrant.py +201 -0
  9. letta/agent_store/storage.py +188 -0
  10. letta/benchmark/benchmark.py +96 -0
  11. letta/benchmark/constants.py +14 -0
  12. letta/cli/cli.py +689 -0
  13. letta/cli/cli_config.py +1282 -0
  14. letta/cli/cli_load.py +166 -0
  15. letta/client/__init__.py +0 -0
  16. letta/client/admin.py +171 -0
  17. letta/client/client.py +2360 -0
  18. letta/client/streaming.py +90 -0
  19. letta/client/utils.py +61 -0
  20. letta/config.py +484 -0
  21. letta/configs/anthropic.json +13 -0
  22. letta/configs/letta_hosted.json +11 -0
  23. letta/configs/openai.json +12 -0
  24. letta/constants.py +134 -0
  25. letta/credentials.py +140 -0
  26. letta/data_sources/connectors.py +247 -0
  27. letta/embeddings.py +218 -0
  28. letta/errors.py +26 -0
  29. letta/functions/__init__.py +0 -0
  30. letta/functions/function_sets/base.py +174 -0
  31. letta/functions/function_sets/extras.py +132 -0
  32. letta/functions/functions.py +105 -0
  33. letta/functions/schema_generator.py +205 -0
  34. letta/humans/__init__.py +0 -0
  35. letta/humans/examples/basic.txt +1 -0
  36. letta/humans/examples/cs_phd.txt +9 -0
  37. letta/interface.py +314 -0
  38. letta/llm_api/__init__.py +0 -0
  39. letta/llm_api/anthropic.py +383 -0
  40. letta/llm_api/azure_openai.py +155 -0
  41. letta/llm_api/cohere.py +396 -0
  42. letta/llm_api/google_ai.py +468 -0
  43. letta/llm_api/llm_api_tools.py +485 -0
  44. letta/llm_api/openai.py +470 -0
  45. letta/local_llm/README.md +3 -0
  46. letta/local_llm/__init__.py +0 -0
  47. letta/local_llm/chat_completion_proxy.py +279 -0
  48. letta/local_llm/constants.py +31 -0
  49. letta/local_llm/function_parser.py +68 -0
  50. letta/local_llm/grammars/__init__.py +0 -0
  51. letta/local_llm/grammars/gbnf_grammar_generator.py +1324 -0
  52. letta/local_llm/grammars/json.gbnf +26 -0
  53. letta/local_llm/grammars/json_func_calls_with_inner_thoughts.gbnf +32 -0
  54. letta/local_llm/groq/api.py +97 -0
  55. letta/local_llm/json_parser.py +202 -0
  56. letta/local_llm/koboldcpp/api.py +62 -0
  57. letta/local_llm/koboldcpp/settings.py +23 -0
  58. letta/local_llm/llamacpp/api.py +58 -0
  59. letta/local_llm/llamacpp/settings.py +22 -0
  60. letta/local_llm/llm_chat_completion_wrappers/__init__.py +0 -0
  61. letta/local_llm/llm_chat_completion_wrappers/airoboros.py +452 -0
  62. letta/local_llm/llm_chat_completion_wrappers/chatml.py +470 -0
  63. letta/local_llm/llm_chat_completion_wrappers/configurable_wrapper.py +387 -0
  64. letta/local_llm/llm_chat_completion_wrappers/dolphin.py +246 -0
  65. letta/local_llm/llm_chat_completion_wrappers/llama3.py +345 -0
  66. letta/local_llm/llm_chat_completion_wrappers/simple_summary_wrapper.py +156 -0
  67. letta/local_llm/llm_chat_completion_wrappers/wrapper_base.py +11 -0
  68. letta/local_llm/llm_chat_completion_wrappers/zephyr.py +345 -0
  69. letta/local_llm/lmstudio/api.py +100 -0
  70. letta/local_llm/lmstudio/settings.py +29 -0
  71. letta/local_llm/ollama/api.py +88 -0
  72. letta/local_llm/ollama/settings.py +32 -0
  73. letta/local_llm/settings/__init__.py +0 -0
  74. letta/local_llm/settings/deterministic_mirostat.py +45 -0
  75. letta/local_llm/settings/settings.py +72 -0
  76. letta/local_llm/settings/simple.py +28 -0
  77. letta/local_llm/utils.py +265 -0
  78. letta/local_llm/vllm/api.py +63 -0
  79. letta/local_llm/webui/api.py +60 -0
  80. letta/local_llm/webui/legacy_api.py +58 -0
  81. letta/local_llm/webui/legacy_settings.py +23 -0
  82. letta/local_llm/webui/settings.py +24 -0
  83. letta/log.py +76 -0
  84. letta/main.py +437 -0
  85. letta/memory.py +440 -0
  86. letta/metadata.py +884 -0
  87. letta/openai_backcompat/__init__.py +0 -0
  88. letta/openai_backcompat/openai_object.py +437 -0
  89. letta/persistence_manager.py +148 -0
  90. letta/personas/__init__.py +0 -0
  91. letta/personas/examples/anna_pa.txt +13 -0
  92. letta/personas/examples/google_search_persona.txt +15 -0
  93. letta/personas/examples/memgpt_doc.txt +6 -0
  94. letta/personas/examples/memgpt_starter.txt +4 -0
  95. letta/personas/examples/sam.txt +14 -0
  96. letta/personas/examples/sam_pov.txt +14 -0
  97. letta/personas/examples/sam_simple_pov_gpt35.txt +13 -0
  98. letta/personas/examples/sqldb/test.db +0 -0
  99. letta/prompts/__init__.py +0 -0
  100. letta/prompts/gpt_summarize.py +14 -0
  101. letta/prompts/gpt_system.py +26 -0
  102. letta/prompts/system/memgpt_base.txt +49 -0
  103. letta/prompts/system/memgpt_chat.txt +58 -0
  104. letta/prompts/system/memgpt_chat_compressed.txt +13 -0
  105. letta/prompts/system/memgpt_chat_fstring.txt +51 -0
  106. letta/prompts/system/memgpt_doc.txt +50 -0
  107. letta/prompts/system/memgpt_gpt35_extralong.txt +53 -0
  108. letta/prompts/system/memgpt_intuitive_knowledge.txt +31 -0
  109. letta/prompts/system/memgpt_modified_chat.txt +23 -0
  110. letta/pytest.ini +0 -0
  111. letta/schemas/agent.py +117 -0
  112. letta/schemas/api_key.py +21 -0
  113. letta/schemas/block.py +135 -0
  114. letta/schemas/document.py +21 -0
  115. letta/schemas/embedding_config.py +54 -0
  116. letta/schemas/enums.py +35 -0
  117. letta/schemas/job.py +38 -0
  118. letta/schemas/letta_base.py +80 -0
  119. letta/schemas/letta_message.py +175 -0
  120. letta/schemas/letta_request.py +23 -0
  121. letta/schemas/letta_response.py +28 -0
  122. letta/schemas/llm_config.py +54 -0
  123. letta/schemas/memory.py +224 -0
  124. letta/schemas/message.py +727 -0
  125. letta/schemas/openai/chat_completion_request.py +123 -0
  126. letta/schemas/openai/chat_completion_response.py +136 -0
  127. letta/schemas/openai/chat_completions.py +123 -0
  128. letta/schemas/openai/embedding_response.py +11 -0
  129. letta/schemas/openai/openai.py +157 -0
  130. letta/schemas/organization.py +20 -0
  131. letta/schemas/passage.py +80 -0
  132. letta/schemas/source.py +62 -0
  133. letta/schemas/tool.py +143 -0
  134. letta/schemas/usage.py +18 -0
  135. letta/schemas/user.py +33 -0
  136. letta/server/__init__.py +0 -0
  137. letta/server/constants.py +6 -0
  138. letta/server/rest_api/__init__.py +0 -0
  139. letta/server/rest_api/admin/__init__.py +0 -0
  140. letta/server/rest_api/admin/agents.py +21 -0
  141. letta/server/rest_api/admin/tools.py +83 -0
  142. letta/server/rest_api/admin/users.py +98 -0
  143. letta/server/rest_api/app.py +193 -0
  144. letta/server/rest_api/auth/__init__.py +0 -0
  145. letta/server/rest_api/auth/index.py +43 -0
  146. letta/server/rest_api/auth_token.py +22 -0
  147. letta/server/rest_api/interface.py +726 -0
  148. letta/server/rest_api/routers/__init__.py +0 -0
  149. letta/server/rest_api/routers/openai/__init__.py +0 -0
  150. letta/server/rest_api/routers/openai/assistants/__init__.py +0 -0
  151. letta/server/rest_api/routers/openai/assistants/assistants.py +115 -0
  152. letta/server/rest_api/routers/openai/assistants/schemas.py +121 -0
  153. letta/server/rest_api/routers/openai/assistants/threads.py +336 -0
  154. letta/server/rest_api/routers/openai/chat_completions/__init__.py +0 -0
  155. letta/server/rest_api/routers/openai/chat_completions/chat_completions.py +131 -0
  156. letta/server/rest_api/routers/v1/__init__.py +15 -0
  157. letta/server/rest_api/routers/v1/agents.py +543 -0
  158. letta/server/rest_api/routers/v1/blocks.py +73 -0
  159. letta/server/rest_api/routers/v1/jobs.py +46 -0
  160. letta/server/rest_api/routers/v1/llms.py +28 -0
  161. letta/server/rest_api/routers/v1/organizations.py +61 -0
  162. letta/server/rest_api/routers/v1/sources.py +199 -0
  163. letta/server/rest_api/routers/v1/tools.py +103 -0
  164. letta/server/rest_api/routers/v1/users.py +109 -0
  165. letta/server/rest_api/static_files.py +74 -0
  166. letta/server/rest_api/utils.py +69 -0
  167. letta/server/server.py +1995 -0
  168. letta/server/startup.sh +8 -0
  169. letta/server/static_files/assets/index-0cbf7ad5.js +274 -0
  170. letta/server/static_files/assets/index-156816da.css +1 -0
  171. letta/server/static_files/assets/index-486e3228.js +274 -0
  172. letta/server/static_files/favicon.ico +0 -0
  173. letta/server/static_files/index.html +39 -0
  174. letta/server/static_files/memgpt_logo_transparent.png +0 -0
  175. letta/server/utils.py +46 -0
  176. letta/server/ws_api/__init__.py +0 -0
  177. letta/server/ws_api/example_client.py +104 -0
  178. letta/server/ws_api/interface.py +108 -0
  179. letta/server/ws_api/protocol.py +100 -0
  180. letta/server/ws_api/server.py +145 -0
  181. letta/settings.py +165 -0
  182. letta/streaming_interface.py +396 -0
  183. letta/system.py +207 -0
  184. letta/utils.py +1065 -0
  185. letta_nightly-0.1.7.dev20240924104148.dist-info/LICENSE +190 -0
  186. letta_nightly-0.1.7.dev20240924104148.dist-info/METADATA +98 -0
  187. letta_nightly-0.1.7.dev20240924104148.dist-info/RECORD +189 -0
  188. letta_nightly-0.1.7.dev20240924104148.dist-info/WHEEL +4 -0
  189. letta_nightly-0.1.7.dev20240924104148.dist-info/entry_points.txt +3 -0
letta/cli/cli_load.py ADDED
@@ -0,0 +1,166 @@
1
+ """
2
+ This file contains functions for loading data into Letta's archival storage.
3
+
4
+ Data can be loaded with the following command, once a load function is defined:
5
+ ```
6
+ letta load <data-connector-type> --name <dataset-name> [ADDITIONAL ARGS]
7
+ ```
8
+
9
+ """
10
+
11
+ import uuid
12
+ from typing import Annotated, List, Optional
13
+
14
+ import typer
15
+
16
+ from letta import create_client
17
+ from letta.data_sources.connectors import DirectoryConnector
18
+
19
+ app = typer.Typer()
20
+
21
+ # NOTE: not supported due to llama-index breaking things (please reach out if you still need it)
22
+ # @app.command("index")
23
+ # def load_index(
24
+ # name: Annotated[str, typer.Option(help="Name of dataset to load.")],
25
+ # dir: Annotated[Optional[str], typer.Option(help="Path to directory containing index.")] = None,
26
+ # user_id: Annotated[Optional[uuid.UUID], typer.Option(help="User ID to associate with dataset.")] = None,
27
+ # ):
28
+ # """Load a LlamaIndex saved VectorIndex into Letta"""
29
+ # if user_id is None:
30
+ # config = LettaConfig.load()
31
+ # user_id = uuid.UUID(config.anon_clientid)
32
+ #
33
+ # try:
34
+ # # load index data
35
+ # storage_context = StorageContext.from_defaults(persist_dir=dir)
36
+ # loaded_index = load_index_from_storage(storage_context)
37
+ #
38
+ # # hacky code to extract out passages/embeddings (thanks a lot, llama index)
39
+ # embed_dict = loaded_index._vector_store._data.embedding_dict
40
+ # node_dict = loaded_index._docstore.docs
41
+ #
42
+ # # create storage connector
43
+ # config = LettaConfig.load()
44
+ # if user_id is None:
45
+ # user_id = uuid.UUID(config.anon_clientid)
46
+ #
47
+ # passages = []
48
+ # for node_id, node in node_dict.items():
49
+ # vector = embed_dict[node_id]
50
+ # node.embedding = vector
51
+ # # assume embedding are the same as config
52
+ # passages.append(
53
+ # Passage(
54
+ # text=node.text,
55
+ # embedding=np.array(vector),
56
+ # embedding_dim=config.default_embedding_config.embedding_dim,
57
+ # embedding_model=config.default_embedding_config.embedding_model,
58
+ # )
59
+ # )
60
+ # assert config.default_embedding_config.embedding_dim == len(
61
+ # vector
62
+ # ), f"Expected embedding dimension {config.default_embedding_config.embedding_dim}, got {len(vector)}"
63
+ #
64
+ # if len(passages) == 0:
65
+ # raise ValueError(f"No passages found in index {dir}")
66
+ #
67
+ # insert_passages_into_source(passages, name, user_id, config)
68
+ # except ValueError as e:
69
+ # typer.secho(f"Failed to load index from provided information.\n{e}", fg=typer.colors.RED)
70
+
71
+
72
+ default_extensions = ".txt,.md,.pdf"
73
+
74
+
75
+ @app.command("directory")
76
+ def load_directory(
77
+ name: Annotated[str, typer.Option(help="Name of dataset to load.")],
78
+ input_dir: Annotated[Optional[str], typer.Option(help="Path to directory containing dataset.")] = None,
79
+ input_files: Annotated[List[str], typer.Option(help="List of paths to files containing dataset.")] = [],
80
+ recursive: Annotated[bool, typer.Option(help="Recursively search for files in directory.")] = False,
81
+ extensions: Annotated[str, typer.Option(help="Comma separated list of file extensions to load")] = default_extensions,
82
+ user_id: Annotated[Optional[uuid.UUID], typer.Option(help="User ID to associate with dataset.")] = None, # TODO: remove
83
+ description: Annotated[Optional[str], typer.Option(help="Description of the source.")] = None,
84
+ ):
85
+ client = create_client()
86
+
87
+ # create connector
88
+ connector = DirectoryConnector(input_files=input_files, input_directory=input_dir, recursive=recursive, extensions=extensions)
89
+
90
+ # create source
91
+ source = client.create_source(name=name)
92
+
93
+ # load data
94
+ try:
95
+ client.load_data(connector, source_name=name)
96
+ except Exception as e:
97
+ typer.secho(f"Failed to load data from provided information.\n{e}", fg=typer.colors.RED)
98
+ client.delete_source(source.id)
99
+
100
+
101
+ # @app.command("webpage")
102
+ # def load_webpage(
103
+ # name: Annotated[str, typer.Option(help="Name of dataset to load.")],
104
+ # urls: Annotated[List[str], typer.Option(help="List of urls to load.")],
105
+ # ):
106
+ # try:
107
+ # from llama_index.readers.web import SimpleWebPageReader
108
+ #
109
+ # docs = SimpleWebPageReader(html_to_text=True).load_data(urls)
110
+ # store_docs(name, docs)
111
+ #
112
+ # except ValueError as e:
113
+ # typer.secho(f"Failed to load webpage from provided information.\n{e}", fg=typer.colors.RED)
114
+
115
+
116
+ @app.command("vector-database")
117
+ def load_vector_database(
118
+ name: Annotated[str, typer.Option(help="Name of dataset to load.")],
119
+ uri: Annotated[str, typer.Option(help="Database URI.")],
120
+ table_name: Annotated[str, typer.Option(help="Name of table containing data.")],
121
+ text_column: Annotated[str, typer.Option(help="Name of column containing text.")],
122
+ embedding_column: Annotated[str, typer.Option(help="Name of column containing embedding.")],
123
+ user_id: Annotated[Optional[uuid.UUID], typer.Option(help="User ID to associate with dataset.")] = None,
124
+ ):
125
+ """Load pre-computed embeddings into Letta from a database."""
126
+ raise NotImplementedError
127
+ # try:
128
+ # config = LettaConfig.load()
129
+ # connector = VectorDBConnector(
130
+ # uri=uri,
131
+ # table_name=table_name,
132
+ # text_column=text_column,
133
+ # embedding_column=embedding_column,
134
+ # embedding_dim=config.default_embedding_config.embedding_dim,
135
+ # )
136
+ # if not user_id:
137
+ # user_id = uuid.UUID(config.anon_clientid)
138
+
139
+ # ms = MetadataStore(config)
140
+ # source = Source(
141
+ # name=name,
142
+ # user_id=user_id,
143
+ # embedding_model=config.default_embedding_config.embedding_model,
144
+ # embedding_dim=config.default_embedding_config.embedding_dim,
145
+ # )
146
+ # ms.create_source(source)
147
+ # passage_storage = StorageConnector.get_storage_connector(TableType.PASSAGES, config, user_id)
148
+ # # TODO: also get document store
149
+
150
+ # # ingest data into passage/document store
151
+ # try:
152
+ # num_passages, num_documents = load_data(
153
+ # connector=connector,
154
+ # source=source,
155
+ # embedding_config=config.default_embedding_config,
156
+ # document_store=None,
157
+ # passage_store=passage_storage,
158
+ # )
159
+ # print(f"Loaded {num_passages} passages and {num_documents} documents from {name}")
160
+ # except Exception as e:
161
+ # typer.secho(f"Failed to load data from provided information.\n{e}", fg=typer.colors.RED)
162
+ # ms.delete_source(source_id=source.id)
163
+
164
+ # except ValueError as e:
165
+ # typer.secho(f"Failed to load VectorDB from provided information.\n{e}", fg=typer.colors.RED)
166
+ # raise
File without changes
letta/client/admin.py ADDED
@@ -0,0 +1,171 @@
1
+ from typing import List, Optional
2
+
3
+ import requests
4
+ from requests import HTTPError
5
+
6
+ from letta.functions.functions import parse_source_code
7
+ from letta.functions.schema_generator import generate_schema
8
+ from letta.schemas.api_key import APIKey, APIKeyCreate
9
+ from letta.schemas.organization import Organization, OrganizationCreate
10
+ from letta.schemas.user import User, UserCreate
11
+
12
+
13
+ class Admin:
14
+ """
15
+ Admin client allows admin-level operations on the Letta server.
16
+ - Creating users
17
+ - Generating user keys
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ base_url: str,
23
+ token: str,
24
+ api_prefix: str = "v1",
25
+ ):
26
+ self.base_url = base_url
27
+ self.api_prefix = api_prefix
28
+ self.token = token
29
+ self.headers = {"accept": "application/json", "content-type": "application/json", "authorization": f"Bearer {token}"}
30
+
31
+ def get_users(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[User]:
32
+ params = {}
33
+ if cursor:
34
+ params["cursor"] = str(cursor)
35
+ if limit:
36
+ params["limit"] = limit
37
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/admin/users", params=params, headers=self.headers)
38
+ if response.status_code != 200:
39
+ raise HTTPError(response.json())
40
+ return [User(**user) for user in response.json()]
41
+
42
+ def create_key(self, user_id: str, key_name: Optional[str] = None) -> APIKey:
43
+ request = APIKeyCreate(user_id=user_id, name=key_name)
44
+ response = requests.post(f"{self.base_url}/{self.api_prefix}/admin/users/keys", headers=self.headers, json=request.model_dump())
45
+ if response.status_code != 200:
46
+ raise HTTPError(response.json())
47
+ return APIKey(**response.json())
48
+
49
+ def get_keys(self, user_id: str) -> List[APIKey]:
50
+ params = {"user_id": str(user_id)}
51
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/admin/users/keys", params=params, headers=self.headers)
52
+ if response.status_code != 200:
53
+ raise HTTPError(response.json())
54
+ return [APIKey(**key) for key in response.json()]
55
+
56
+ def delete_key(self, api_key: str) -> APIKey:
57
+ params = {"api_key": api_key}
58
+ response = requests.delete(f"{self.base_url}/{self.api_prefix}/admin/users/keys", params=params, headers=self.headers)
59
+ if response.status_code != 200:
60
+ raise HTTPError(response.json())
61
+ return APIKey(**response.json())
62
+
63
+ def create_user(self, name: Optional[str] = None, org_id: Optional[str] = None) -> User:
64
+ request = UserCreate(name=name, org_id=org_id)
65
+ response = requests.post(f"{self.base_url}/{self.api_prefix}/admin/users", headers=self.headers, json=request.model_dump())
66
+ if response.status_code != 200:
67
+ raise HTTPError(response.json())
68
+ response_json = response.json()
69
+ return User(**response_json)
70
+
71
+ def delete_user(self, user_id: str) -> User:
72
+ params = {"user_id": str(user_id)}
73
+ response = requests.delete(f"{self.base_url}/{self.api_prefix}/admin/users", params=params, headers=self.headers)
74
+ if response.status_code != 200:
75
+ raise HTTPError(response.json())
76
+ return User(**response.json())
77
+
78
+ def create_organization(self, name: Optional[str] = None) -> Organization:
79
+ request = OrganizationCreate(name=name)
80
+ response = requests.post(f"{self.base_url}/{self.api_prefix}/admin/orgs", headers=self.headers, json=request.model_dump())
81
+ if response.status_code != 200:
82
+ raise HTTPError(response.json())
83
+ response_json = response.json()
84
+ return Organization(**response_json)
85
+
86
+ def delete_organization(self, org_id: str) -> Organization:
87
+ params = {"org_id": str(org_id)}
88
+ response = requests.delete(f"{self.base_url}/{self.api_prefix}/admin/orgs", params=params, headers=self.headers)
89
+ if response.status_code != 200:
90
+ raise HTTPError(response.json())
91
+ return Organization(**response.json())
92
+
93
+ def get_organizations(self, cursor: Optional[str] = None, limit: Optional[int] = 50) -> List[Organization]:
94
+ params = {}
95
+ if cursor:
96
+ params["cursor"] = str(cursor)
97
+ if limit:
98
+ params["limit"] = limit
99
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/admin/orgs", params=params, headers=self.headers)
100
+ if response.status_code != 200:
101
+ raise HTTPError(response.json())
102
+ return [Organization(**org) for org in response.json()]
103
+
104
+ def _reset_server(self):
105
+ # DANGER: this will delete all users and keys
106
+ # clear all state associated with users
107
+ # TODO: clear out all agents, presets, etc.
108
+ users = self.get_users()
109
+ for user in users:
110
+ keys = self.get_keys(user.id)
111
+ for key in keys:
112
+ self.delete_key(key.key)
113
+ self.delete_user(user.id)
114
+
115
+ # tools
116
+ def create_tool(
117
+ self,
118
+ func,
119
+ name: Optional[str] = None,
120
+ update: Optional[bool] = True, # TODO: actually use this
121
+ tags: Optional[List[str]] = None,
122
+ ):
123
+ """Create a tool
124
+ Args:
125
+ func (callable): The function to create a tool for.
126
+ tags (Optional[List[str]], optional): Tags for the tool. Defaults to None.
127
+ update (bool, optional): Update the tool if it already exists. Defaults to True.
128
+ Returns:
129
+ Tool object
130
+ """
131
+
132
+ # TODO: check if tool already exists
133
+ # TODO: how to load modules?
134
+ # parse source code/schema
135
+ source_code = parse_source_code(func)
136
+ json_schema = generate_schema(func, name)
137
+ source_type = "python"
138
+ json_schema["name"]
139
+
140
+ if "memory" in tags:
141
+ # special modifications to memory functions
142
+ # self.memory -> self.memory.memory, since Agent.memory.memory needs to be modified (not BaseMemory.memory)
143
+ source_code = source_code.replace("self.memory", "self.memory.memory")
144
+
145
+ # create data
146
+ data = {"source_code": source_code, "source_type": source_type, "tags": tags, "json_schema": json_schema}
147
+ CreateToolRequest(**data) # validate
148
+
149
+ # make REST request
150
+ response = requests.post(f"{self.base_url}/{self.api_prefix}/admin/tools", json=data, headers=self.headers)
151
+ if response.status_code != 200:
152
+ raise ValueError(f"Failed to create tool: {response.text}")
153
+ return ToolModel(**response.json())
154
+
155
+ def list_tools(self):
156
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/admin/tools", headers=self.headers)
157
+ return ListToolsResponse(**response.json()).tools
158
+
159
+ def delete_tool(self, name: str):
160
+ response = requests.delete(f"{self.base_url}/{self.api_prefix}/admin/tools/{name}", headers=self.headers)
161
+ if response.status_code != 200:
162
+ raise ValueError(f"Failed to delete tool: {response.text}")
163
+ return response.json()
164
+
165
+ def get_tool(self, name: str):
166
+ response = requests.get(f"{self.base_url}/{self.api_prefix}/admin/tools/{name}", headers=self.headers)
167
+ if response.status_code == 404:
168
+ return None
169
+ elif response.status_code != 200:
170
+ raise ValueError(f"Failed to get tool: {response.text}")
171
+ return ToolModel(**response.json())