symbolicai 0.21.0__py3-none-any.whl → 1.1.0__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.
Files changed (134) hide show
  1. symai/__init__.py +269 -173
  2. symai/backend/base.py +123 -110
  3. symai/backend/engines/drawing/engine_bfl.py +45 -44
  4. symai/backend/engines/drawing/engine_gpt_image.py +112 -97
  5. symai/backend/engines/embedding/engine_llama_cpp.py +63 -52
  6. symai/backend/engines/embedding/engine_openai.py +25 -21
  7. symai/backend/engines/execute/engine_python.py +19 -18
  8. symai/backend/engines/files/engine_io.py +104 -95
  9. symai/backend/engines/imagecaptioning/engine_blip2.py +28 -24
  10. symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +102 -79
  11. symai/backend/engines/index/engine_pinecone.py +124 -97
  12. symai/backend/engines/index/engine_qdrant.py +1011 -0
  13. symai/backend/engines/index/engine_vectordb.py +84 -56
  14. symai/backend/engines/lean/engine_lean4.py +96 -52
  15. symai/backend/engines/neurosymbolic/__init__.py +41 -13
  16. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +330 -248
  17. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +329 -264
  18. symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
  19. symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +118 -88
  20. symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +344 -299
  21. symai/backend/engines/neurosymbolic/engine_groq.py +173 -115
  22. symai/backend/engines/neurosymbolic/engine_huggingface.py +114 -84
  23. symai/backend/engines/neurosymbolic/engine_llama_cpp.py +144 -118
  24. symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +415 -307
  25. symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +394 -231
  26. symai/backend/engines/ocr/engine_apilayer.py +23 -27
  27. symai/backend/engines/output/engine_stdout.py +10 -13
  28. symai/backend/engines/{webscraping → scrape}/engine_requests.py +101 -54
  29. symai/backend/engines/search/engine_openai.py +100 -88
  30. symai/backend/engines/search/engine_parallel.py +665 -0
  31. symai/backend/engines/search/engine_perplexity.py +44 -45
  32. symai/backend/engines/search/engine_serpapi.py +37 -34
  33. symai/backend/engines/speech_to_text/engine_local_whisper.py +54 -51
  34. symai/backend/engines/symbolic/engine_wolframalpha.py +15 -9
  35. symai/backend/engines/text_to_speech/engine_openai.py +20 -26
  36. symai/backend/engines/text_vision/engine_clip.py +39 -37
  37. symai/backend/engines/userinput/engine_console.py +5 -6
  38. symai/backend/mixin/__init__.py +13 -0
  39. symai/backend/mixin/anthropic.py +48 -38
  40. symai/backend/mixin/deepseek.py +6 -5
  41. symai/backend/mixin/google.py +7 -4
  42. symai/backend/mixin/groq.py +2 -4
  43. symai/backend/mixin/openai.py +140 -110
  44. symai/backend/settings.py +87 -20
  45. symai/chat.py +216 -123
  46. symai/collect/__init__.py +7 -1
  47. symai/collect/dynamic.py +80 -70
  48. symai/collect/pipeline.py +67 -51
  49. symai/collect/stats.py +161 -109
  50. symai/components.py +707 -360
  51. symai/constraints.py +24 -12
  52. symai/core.py +1857 -1233
  53. symai/core_ext.py +83 -80
  54. symai/endpoints/api.py +166 -104
  55. symai/extended/.DS_Store +0 -0
  56. symai/extended/__init__.py +46 -12
  57. symai/extended/api_builder.py +29 -21
  58. symai/extended/arxiv_pdf_parser.py +23 -14
  59. symai/extended/bibtex_parser.py +9 -6
  60. symai/extended/conversation.py +156 -126
  61. symai/extended/document.py +50 -30
  62. symai/extended/file_merger.py +57 -14
  63. symai/extended/graph.py +51 -32
  64. symai/extended/html_style_template.py +18 -14
  65. symai/extended/interfaces/blip_2.py +2 -3
  66. symai/extended/interfaces/clip.py +4 -3
  67. symai/extended/interfaces/console.py +9 -1
  68. symai/extended/interfaces/dall_e.py +4 -2
  69. symai/extended/interfaces/file.py +2 -0
  70. symai/extended/interfaces/flux.py +4 -2
  71. symai/extended/interfaces/gpt_image.py +16 -7
  72. symai/extended/interfaces/input.py +2 -1
  73. symai/extended/interfaces/llava.py +1 -2
  74. symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +4 -3
  75. symai/extended/interfaces/naive_vectordb.py +9 -10
  76. symai/extended/interfaces/ocr.py +5 -3
  77. symai/extended/interfaces/openai_search.py +2 -0
  78. symai/extended/interfaces/parallel.py +30 -0
  79. symai/extended/interfaces/perplexity.py +2 -0
  80. symai/extended/interfaces/pinecone.py +12 -9
  81. symai/extended/interfaces/python.py +2 -0
  82. symai/extended/interfaces/serpapi.py +3 -1
  83. symai/extended/interfaces/terminal.py +2 -4
  84. symai/extended/interfaces/tts.py +3 -2
  85. symai/extended/interfaces/whisper.py +3 -2
  86. symai/extended/interfaces/wolframalpha.py +2 -1
  87. symai/extended/metrics/__init__.py +11 -1
  88. symai/extended/metrics/similarity.py +14 -13
  89. symai/extended/os_command.py +39 -29
  90. symai/extended/packages/__init__.py +29 -3
  91. symai/extended/packages/symdev.py +51 -43
  92. symai/extended/packages/sympkg.py +41 -35
  93. symai/extended/packages/symrun.py +63 -50
  94. symai/extended/repo_cloner.py +14 -12
  95. symai/extended/seo_query_optimizer.py +15 -13
  96. symai/extended/solver.py +116 -91
  97. symai/extended/summarizer.py +12 -10
  98. symai/extended/taypan_interpreter.py +17 -18
  99. symai/extended/vectordb.py +122 -92
  100. symai/formatter/__init__.py +9 -1
  101. symai/formatter/formatter.py +51 -47
  102. symai/formatter/regex.py +70 -69
  103. symai/functional.py +325 -176
  104. symai/imports.py +190 -147
  105. symai/interfaces.py +57 -28
  106. symai/memory.py +45 -35
  107. symai/menu/screen.py +28 -19
  108. symai/misc/console.py +66 -56
  109. symai/misc/loader.py +8 -5
  110. symai/models/__init__.py +17 -1
  111. symai/models/base.py +395 -236
  112. symai/models/errors.py +1 -2
  113. symai/ops/__init__.py +32 -22
  114. symai/ops/measures.py +24 -25
  115. symai/ops/primitives.py +1149 -731
  116. symai/post_processors.py +58 -50
  117. symai/pre_processors.py +86 -82
  118. symai/processor.py +21 -13
  119. symai/prompts.py +764 -685
  120. symai/server/huggingface_server.py +135 -49
  121. symai/server/llama_cpp_server.py +21 -11
  122. symai/server/qdrant_server.py +206 -0
  123. symai/shell.py +100 -42
  124. symai/shellsv.py +700 -492
  125. symai/strategy.py +630 -346
  126. symai/symbol.py +368 -322
  127. symai/utils.py +100 -78
  128. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/METADATA +22 -10
  129. symbolicai-1.1.0.dist-info/RECORD +168 -0
  130. symbolicai-0.21.0.dist-info/RECORD +0 -162
  131. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/WHEEL +0 -0
  132. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/entry_points.txt +0 -0
  133. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/licenses/LICENSE +0 -0
  134. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/top_level.txt +0 -0
symai/endpoints/api.py CHANGED
@@ -1,65 +1,67 @@
1
1
  import importlib
2
2
  import inspect
3
3
  import pickle
4
- import redis
4
+ from typing import Any, Generic, TypeVar
5
5
 
6
- from redis.exceptions import ConnectionError
7
- from fastapi import FastAPI, APIRouter, HTTPException, Security, status
8
- from fastapi.security import APIKeyHeader
6
+ import redis
7
+ from fastapi import APIRouter, FastAPI, HTTPException, Security, status
9
8
  from fastapi.middleware.cors import CORSMiddleware
9
+ from fastapi.security import APIKeyHeader
10
10
  from pydantic import BaseModel
11
- from typing import Any, Generic, TypeVar, Dict, List, Optional, Union
11
+ from redis.exceptions import ConnectionError as RedisConnectionError
12
12
 
13
13
  from symai.backend import settings
14
14
 
15
15
  from .. import core_ext
16
- from ..symbol import Symbol, Expression
17
-
16
+ from ..symbol import Expression, Symbol
17
+ from ..utils import UserMessage
18
18
 
19
19
  # Configure Redis server connection parameters and executable path
20
- HOST = 'localhost'
21
- PORT = 6379
20
+ HOST = "localhost"
21
+ PORT = 6379
22
22
  DEBUG = True
23
- API_KEY = settings.SYMAI_CONFIG.get('FASTAPI_API_KEY', None)
23
+ API_KEY = settings.SYMAI_CONFIG.get("FASTAPI_API_KEY", None)
24
+
24
25
 
25
26
  def is_redis_running(host: str, port: int) -> bool:
26
27
  """Check if a Redis server is running at the given host and port."""
27
28
  try:
28
29
  r = redis.Redis(host=host, port=port)
29
30
  r.ping()
30
- print(f"Redis server is running at {host}:{port}")
31
+ UserMessage(f"Redis server is running at {host}:{port}")
31
32
  return True
32
- except ConnectionError:
33
- print(f"Redis server is not running at {host}:{port} or is not reachable - falling back to in-memory storage")
33
+ except RedisConnectionError:
34
+ UserMessage(
35
+ f"Redis server is not running at {host}:{port} or is not reachable - falling back to in-memory storage"
36
+ )
34
37
  return False
35
38
 
36
39
 
37
- # Create a generic type variable
38
- T = TypeVar('T')
40
+ T = TypeVar("T")
39
41
 
40
42
 
41
43
  class GenericRepository(Generic[T]):
42
44
  def __init__(self, redis_client: redis.Redis, id_key: str, use_redis: bool = True):
43
- self.storage: Dict[str, T] = {} # In-memory dictionary to mock Redis
44
- self.use_redis = use_redis
45
- self.id_key = id_key # Key used for storing the incremental ID counter
46
- self.redis_client = redis_client
45
+ self.storage: dict[str, T] = {} # In-memory dictionary to mock Redis
46
+ self.use_redis = use_redis
47
+ self.id_key = id_key # Key used for storing the incremental ID counter
48
+ self.redis_client = redis_client
47
49
  if self.use_redis:
48
- self.set = self._store_redis
49
- self.get = self._retrieve_redis
50
- self.delete = self._delete_redis
51
- self.uid = self._generate_id_redis
50
+ self.set = self._store_redis
51
+ self.get = self._retrieve_redis
52
+ self.delete = self._delete_redis
53
+ self.uid = self._generate_id_redis
52
54
  else:
53
- self.set = self._store_memory
54
- self.get = self._retrieve_memory
55
- self.delete = self._delete_memory
56
- self.uid = self._generate_id_memory
55
+ self.set = self._store_memory
56
+ self.get = self._retrieve_memory
57
+ self.delete = self._delete_memory
58
+ self.uid = self._generate_id_memory
57
59
 
58
60
  def _deserialize_object(self, serialized_item: bytes) -> T:
59
61
  """Deserialize the byte object back into a Python object of type T."""
60
62
  return pickle.loads(serialized_item)
61
63
 
62
- def _serialize_object(self, item_id: str, item: T) -> None:
64
+ def _serialize_object(self, _item_id: str, item: T) -> None:
63
65
  return pickle.dumps(item)
64
66
 
65
67
  def _store_memory(self, item_id: str, item: T) -> None:
@@ -76,7 +78,7 @@ class GenericRepository(Generic[T]):
76
78
 
77
79
  def _generate_id_memory(self) -> str:
78
80
  id_ = len(self.storage) + 1
79
- return f'{self.id_key}:{id_}'
81
+ return f"{self.id_key}:{id_}"
80
82
 
81
83
  def _store_redis(self, item_id: str, item: T) -> None:
82
84
  item = self._serialize_object(item_id, item)
@@ -85,8 +87,7 @@ class GenericRepository(Generic[T]):
85
87
  def _retrieve_redis(self, item_id: str) -> T:
86
88
  item = self.redis_client.get(item_id)
87
89
  if item:
88
- item = self._deserialize_object(item)
89
- return item
90
+ return self._deserialize_object(item)
90
91
  return None
91
92
 
92
93
  def _delete_redis(self, item_id: str) -> bool:
@@ -94,39 +95,67 @@ class GenericRepository(Generic[T]):
94
95
 
95
96
  def _generate_id_redis(self) -> str:
96
97
  id_ = self.redis_client.incr(self.id_key)
97
- return f'{self.id_key}:{id_}'
98
+ return f"{self.id_key}:{id_}"
98
99
 
99
100
 
100
101
  # Initialize the Redis client
101
102
  redis_client = redis.Redis(
102
- host=HOST, # Or use the host where your Redis server is running
103
- port=PORT, # The default Redis port number
104
- db=0 # The default database index
103
+ host=HOST, # Or use the host where your Redis server is running
104
+ port=PORT, # The default Redis port number
105
+ db=0, # The default database index
105
106
  )
106
107
 
107
108
  # Initialize the FastAPI app and API router
108
- app = FastAPI(title="SymbolicAI API", version="1.0")
109
- api_key_header = APIKeyHeader(name="X-API-Key")
110
- router = APIRouter()
111
- use_redis = is_redis_running(HOST, PORT)
109
+ app = FastAPI(title="SymbolicAI API", version="1.0")
110
+ api_key_header = APIKeyHeader(name="X-API-Key")
111
+ router = APIRouter()
112
+ use_redis = is_redis_running(HOST, PORT)
112
113
 
113
114
  # Instantiate the generic repositories with the counter keys
114
- symbol_repository = GenericRepository[Symbol](redis_client, "sym_id", use_redis=use_redis)
115
- expression_repository = GenericRepository[Expression](redis_client, "expr_id", use_redis=use_redis)
115
+ symbol_repository = GenericRepository[Symbol](redis_client, "sym_id", use_redis=use_redis)
116
+ expression_repository = GenericRepository[Expression](redis_client, "expr_id", use_redis=use_redis)
116
117
  # Register all types which subclass Expression and offer a get() method with default=None
117
118
  component_class_types = {
118
- name: cls for name, cls in inspect.getmembers(importlib.import_module('symai.components'), inspect.isclass) if issubclass(cls, Expression)
119
+ name: cls
120
+ for name, cls in inspect.getmembers(
121
+ importlib.import_module("symai.components"), inspect.isclass
122
+ )
123
+ if issubclass(cls, Expression)
119
124
  }
120
- component_instance_repository = GenericRepository[Union[Symbol, Expression]](redis_client, "comp_id", use_redis=use_redis)
125
+ component_instance_repository = GenericRepository[Symbol | Expression](
126
+ redis_client, "comp_id", use_redis=use_redis
127
+ )
121
128
 
122
- app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
129
+
130
+ def _load_extended_types():
131
+ """Load extended classes lazily to avoid premature engine initialization."""
132
+ extended_module = importlib.import_module("symai.extended")
133
+ personas_module = importlib.import_module("symai.extended.personas")
134
+ sales_module = importlib.import_module("symai.extended.personas.sales")
135
+ student_module = importlib.import_module("symai.extended.personas.student")
136
+ return [
137
+ extended_module.Conversation,
138
+ personas_module.Persona,
139
+ personas_module.Dialogue,
140
+ student_module.MaxTenner,
141
+ sales_module.ErikJames,
142
+ ]
143
+
144
+
145
+ app.add_middleware(
146
+ CORSMiddleware,
147
+ allow_origins=["*"],
148
+ allow_credentials=True,
149
+ allow_methods=["*"],
150
+ allow_headers=["*"],
151
+ )
123
152
 
124
153
  ### Symbols Endpoints ###
125
154
 
126
155
 
127
156
  class CreateSymbolRequest(BaseModel):
128
- value: Optional[Any] = None
129
- static_context: Optional[str] = ''
157
+ value: Any | None = None
158
+ static_context: str | None = ""
130
159
 
131
160
 
132
161
  class UpdateSymbolRequest(BaseModel):
@@ -135,11 +164,12 @@ class UpdateSymbolRequest(BaseModel):
135
164
 
136
165
 
137
166
  class SymbolMethodRequest(BaseModel):
138
- args: List[Any] = []
139
- kwargs: Dict[str, Any] = {}
167
+ args: list[Any] = []
168
+ kwargs: dict[str, Any] = {}
169
+
140
170
 
141
171
  def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else None) -> str:
142
- if API_KEY == None:
172
+ if API_KEY is None:
143
173
  return True
144
174
  if api_key_header == API_KEY:
145
175
  return api_key_header
@@ -148,8 +178,9 @@ def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else N
148
178
  detail="Invalid or missing API Key",
149
179
  )
150
180
 
181
+
151
182
  @app.post("/symbol/")
152
- def create_symbol(symbol_request: CreateSymbolRequest, api_key: str = Security(get_api_key)):
183
+ def create_symbol(symbol_request: CreateSymbolRequest, _api_key: str = Security(get_api_key)):
153
184
  symbol = Symbol(symbol_request.value, static_context=symbol_request.static_context)
154
185
  symbol_id = symbol_repository.uid()
155
186
  symbol_repository.set(symbol_id, symbol)
@@ -157,7 +188,7 @@ def create_symbol(symbol_request: CreateSymbolRequest, api_key: str = Security(g
157
188
 
158
189
 
159
190
  @app.get("/symbol/{symbol_id}/")
160
- def get_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
191
+ def get_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
161
192
  symbol = symbol_repository.get(symbol_id)
162
193
  if symbol is None:
163
194
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -165,7 +196,9 @@ def get_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
165
196
 
166
197
 
167
198
  @app.patch("/symbol/{symbol_id}/")
168
- def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, api_key: str = Security(get_api_key)):
199
+ def update_symbol(
200
+ symbol_id: str, update_request: UpdateSymbolRequest, _api_key: str = Security(get_api_key)
201
+ ):
169
202
  symbol = symbol_repository.get(symbol_id)
170
203
  if symbol is None:
171
204
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -176,7 +209,7 @@ def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, api_key:
176
209
 
177
210
 
178
211
  @app.delete("/symbol/{symbol_id}/")
179
- def delete_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
212
+ def delete_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
180
213
  symbol = symbol_repository.delete(symbol_id)
181
214
  if symbol is None:
182
215
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -185,13 +218,20 @@ def delete_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
185
218
 
186
219
  @app.post("/symbol/{symbol_id}/{method_name}/")
187
220
  @core_ext.error_logging(debug=DEBUG)
188
- def operate_on_symbol(symbol_id: str, method_name: str, method_request: SymbolMethodRequest, api_key: str = Security(get_api_key)):
221
+ def operate_on_symbol(
222
+ symbol_id: str,
223
+ method_name: str,
224
+ method_request: SymbolMethodRequest,
225
+ _api_key: str = Security(get_api_key),
226
+ ):
189
227
  symbol = symbol_repository.get(symbol_id)
190
228
  if symbol is None:
191
229
  raise HTTPException(status_code=404, detail="Symbol not found")
192
230
  method = getattr(symbol, method_name, None)
193
231
  if method is None or not callable(method):
194
- raise HTTPException(status_code=404, detail=f"Method {method_name} not found or is not callable")
232
+ raise HTTPException(
233
+ status_code=404, detail=f"Method {method_name} not found or is not callable"
234
+ )
195
235
  result = method(*method_request.args, **method_request.kwargs)
196
236
  return {"result": result.json() if isinstance(result, Symbol) else result}
197
237
 
@@ -200,7 +240,7 @@ def operate_on_symbol(symbol_id: str, method_name: str, method_request: SymbolMe
200
240
 
201
241
 
202
242
  class CreateExpressionRequest(BaseModel):
203
- value: Optional[Any] = None
243
+ value: Any | None = None
204
244
 
205
245
 
206
246
  class UpdateExpressionRequest(BaseModel):
@@ -208,7 +248,9 @@ class UpdateExpressionRequest(BaseModel):
208
248
 
209
249
 
210
250
  @app.post("/expression/")
211
- def create_expression(expression_request: CreateExpressionRequest, api_key: str = Security(get_api_key)):
251
+ def create_expression(
252
+ expression_request: CreateExpressionRequest, _api_key: str = Security(get_api_key)
253
+ ):
212
254
  expression = Expression(expression_request.value)
213
255
  expression_id = expression_repository.uid()
214
256
  expression_repository.set(expression_id, expression)
@@ -216,7 +258,7 @@ def create_expression(expression_request: CreateExpressionRequest, api_key: str
216
258
 
217
259
 
218
260
  @app.get("/expression/{expression_id}/")
219
- def get_expression(expression_id: str, api_key: str = Security(get_api_key)):
261
+ def get_expression(expression_id: str, _api_key: str = Security(get_api_key)):
220
262
  expression = expression_repository.get(expression_id)
221
263
  if expression is None:
222
264
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -225,7 +267,9 @@ def get_expression(expression_id: str, api_key: str = Security(get_api_key)):
225
267
 
226
268
  @app.post("/expression/{expression_id}/call/")
227
269
  @core_ext.error_logging(debug=DEBUG)
228
- def call_expression(expression_id: str, method_request: SymbolMethodRequest, api_key: str = Security(get_api_key)):
270
+ def call_expression(
271
+ expression_id: str, method_request: SymbolMethodRequest, _api_key: str = Security(get_api_key)
272
+ ):
229
273
  # Retrieve the expression instance by ID
230
274
  expression = expression_repository.get(expression_id)
231
275
  if expression is None:
@@ -236,19 +280,30 @@ def call_expression(expression_id: str, method_request: SymbolMethodRequest, api
236
280
 
237
281
  @app.post("/expression/{expression_id}/{method_name}/")
238
282
  @core_ext.error_logging(debug=DEBUG)
239
- def operate_on_expression(expression_id: str, method_name: str, method_request: SymbolMethodRequest, api_key: str = Security(get_api_key)):
283
+ def operate_on_expression(
284
+ expression_id: str,
285
+ method_name: str,
286
+ method_request: SymbolMethodRequest,
287
+ _api_key: str = Security(get_api_key),
288
+ ):
240
289
  expression = expression_repository.get(expression_id)
241
290
  if expression is None:
242
291
  raise HTTPException(status_code=404, detail="Expression not found")
243
292
  method = getattr(expression, method_name, None)
244
293
  if method is None or not callable(method):
245
- raise HTTPException(status_code=404, detail=f"Method {method_name} not found or is not callable")
294
+ raise HTTPException(
295
+ status_code=404, detail=f"Method {method_name} not found or is not callable"
296
+ )
246
297
  result = method(*method_request.args, **method_request.kwargs)
247
298
  return {"result": result.json() if isinstance(result, Symbol) else result}
248
299
 
249
300
 
250
301
  @app.patch("/expression/{expression_id}/")
251
- def update_expression(expression_id: str, update_request: UpdateExpressionRequest, api_key: str = Security(get_api_key)):
302
+ def update_expression(
303
+ expression_id: str,
304
+ update_request: UpdateExpressionRequest,
305
+ _api_key: str = Security(get_api_key),
306
+ ):
252
307
  expression = expression_repository.get(expression_id)
253
308
  if expression is None:
254
309
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -259,7 +314,7 @@ def update_expression(expression_id: str, update_request: UpdateExpressionReques
259
314
 
260
315
 
261
316
  @app.delete("/expression/{expression_id}/")
262
- def delete_expression(expression_id: str, api_key: str = Security(get_api_key)):
317
+ def delete_expression(expression_id: str, _api_key: str = Security(get_api_key)):
263
318
  expression = expression_repository.delete(expression_id)
264
319
  if expression is None:
265
320
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -278,25 +333,25 @@ class AddComponentRequest(BaseModel):
278
333
  # Endpoint to instantiate a generic component class and get the ID
279
334
  class CreateComponentGenericRequest(BaseModel):
280
335
  class_name: str
281
- init_args: List[Any] = []
282
- init_kwargs: Dict[str, Any] = {}
336
+ init_args: list[Any] = []
337
+ init_kwargs: dict[str, Any] = {}
283
338
 
284
339
 
285
340
  # Modify the existing GenericRequest
286
341
  class GenericRequest(BaseModel):
287
342
  class_name: str
288
- init_args: List[Any] = {}
289
- init_kwargs: Dict[str, Any] = {}
290
- forward_args: List[ Any] = {}
291
- forward_kwargs: Dict[str, Any] = {}
343
+ init_args: list[Any] = {}
344
+ init_kwargs: dict[str, Any] = {}
345
+ forward_args: list[Any] = {}
346
+ forward_kwargs: dict[str, Any] = {}
292
347
 
293
348
 
294
349
  class UpdateComponentRequest(BaseModel):
295
- update_kwargs: Dict[str, Any] = {}
350
+ update_kwargs: dict[str, Any] = {}
296
351
 
297
352
 
298
353
  @app.post("/components/")
299
- def create_component(request: CreateComponentGenericRequest, api_key: str = Security(get_api_key)):
354
+ def create_component(request: CreateComponentGenericRequest, _api_key: str = Security(get_api_key)):
300
355
  # Retrieve the class from the repository
301
356
  cls = component_class_types.get(request.class_name)
302
357
  if cls is None:
@@ -305,12 +360,14 @@ def create_component(request: CreateComponentGenericRequest, api_key: str = Secu
305
360
  instance = cls(*request.init_args, **request.init_kwargs)
306
361
  # Store the instance with a generated ID and return the ID
307
362
  instance_id = component_instance_repository.uid()
308
- component_instance_repository.set(instance_id, instance) # Assuming component_instance_repository exists
363
+ component_instance_repository.set(
364
+ instance_id, instance
365
+ ) # Assuming component_instance_repository exists
309
366
  return {"id": instance_id}
310
367
 
311
368
 
312
369
  @app.get("/components/{instance_id}/")
313
- def get_component(instance_id: str, api_key: str = Security(get_api_key)):
370
+ def get_component(instance_id: str, _api_key: str = Security(get_api_key)):
314
371
  # Retrieve an instance by its ID from the repository
315
372
  instance = component_instance_repository.get(instance_id)
316
373
  if instance is None:
@@ -321,13 +378,15 @@ def get_component(instance_id: str, api_key: str = Security(get_api_key)):
321
378
  # Endpoint to execute a command on a component instance
322
379
  @app.post("/components/call/")
323
380
  @core_ext.error_logging(debug=DEBUG)
324
- def generic_forward(request: GenericRequest, api_key: str = Security(get_api_key)):
381
+ def generic_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
325
382
  # Dynamically import the class from components module based on request.class_name
326
- components_module = importlib.import_module('.components', package='symai')
383
+ components_module = importlib.import_module(".components", package="symai")
327
384
  cls = getattr(components_module, request.class_name)
328
385
  # Check if cls is subclass of Expression and instantiate
329
386
  if not issubclass(cls, components_module.Expression):
330
- raise ValueError("The provided class name must be a subclass of Expression")
387
+ msg = "The provided class name must be a subclass of Expression"
388
+ UserMessage(msg)
389
+ raise ValueError(msg)
331
390
  # Initialize the class with provided init_args, requiring unpacking **kwargs
332
391
  instance = cls(*request.init_args, **request.init_kwargs)
333
392
  # Call the forward method with provided forward_args, requiring unpacking **kwargs
@@ -339,7 +398,9 @@ def generic_forward(request: GenericRequest, api_key: str = Security(get_api_key
339
398
 
340
399
 
341
400
  @app.patch("/components/{instance_id}/")
342
- def update_component(instance_id: str, update_request: UpdateComponentRequest, api_key: str = Security(get_api_key)):
401
+ def update_component(
402
+ instance_id: str, update_request: UpdateComponentRequest, _api_key: str = Security(get_api_key)
403
+ ):
343
404
  instance = component_instance_repository.get(instance_id)
344
405
  if instance is None:
345
406
  raise HTTPException(status_code=404, detail="Component instance not found")
@@ -350,7 +411,7 @@ def update_component(instance_id: str, update_request: UpdateComponentRequest, a
350
411
 
351
412
 
352
413
  @app.delete("/components/{instance_id}/")
353
- def delete_component(instance_id: str, api_key: str = Security(get_api_key)):
414
+ def delete_component(instance_id: str, _api_key: str = Security(get_api_key)):
354
415
  instance = component_instance_repository.delete(instance_id)
355
416
  if instance is None:
356
417
  raise HTTPException(status_code=404, detail="Component instance not found")
@@ -359,33 +420,29 @@ def delete_component(instance_id: str, api_key: str = Security(get_api_key)):
359
420
 
360
421
  ### Selectively register the endpoints with the API router ###
361
422
 
362
- # extended imports
363
- from ..extended import Conversation
364
- from ..extended.personas import Persona, Dialogue
365
- from ..extended.personas.student import MaxTenner
366
- from ..extended.personas.sales import ErikJames
367
-
368
-
369
- extended_types = [Conversation, Persona, Dialogue, MaxTenner, ErikJames]
423
+ # extended types loaded lazily to avoid early engine configuration
424
+ extended_types = _load_extended_types()
370
425
  # Register only the extended types from the extended_types Union
371
- extended_class_types = {c.__name__: c for c in extended_types}
372
- extended_instance_repository = GenericRepository[extended_types](redis_client, "ext_id", use_redis=use_redis)
426
+ extended_class_types = {c.__name__: c for c in extended_types}
427
+ extended_instance_repository = GenericRepository[extended_types](
428
+ redis_client, "ext_id", use_redis=use_redis
429
+ )
373
430
 
374
431
 
375
432
  # Model definitions for extended classes
376
433
  class CreateExtendedRequest(BaseModel):
377
434
  class_name: str
378
- init_args: List[Any] = []
379
- init_kwargs: Dict[str, Any] = {}
435
+ init_args: list[Any] = []
436
+ init_kwargs: dict[str, Any] = {}
380
437
 
381
438
 
382
439
  class UpdateExtendedRequest(BaseModel):
383
- update_kwargs: Dict[str, Any] = {}
440
+ update_kwargs: dict[str, Any] = {}
384
441
 
385
442
 
386
443
  # Create endpoints for each of the extended classes
387
444
  @app.post("/extended/")
388
- def create_extended(request: CreateExtendedRequest, api_key: str = Security(get_api_key)):
445
+ def create_extended(request: CreateExtendedRequest, _api_key: str = Security(get_api_key)):
389
446
  # Dynamically retrieve the extended class
390
447
  extended_class = extended_class_types.get(request.class_name)
391
448
  if extended_class is None:
@@ -401,7 +458,7 @@ def create_extended(request: CreateExtendedRequest, api_key: str = Security(get_
401
458
  # Endpoint to execute a command on a component instance
402
459
  @app.post("/extended/call/")
403
460
  @core_ext.error_logging(debug=DEBUG)
404
- def extended_forward(request: GenericRequest, api_key: str = Security(get_api_key)):
461
+ def extended_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
405
462
  # Dynamically import the class from components module based on request.class_name
406
463
  try:
407
464
  # get request.class_name from extended_types if it's a type of extended_types
@@ -409,7 +466,9 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
409
466
  # look for the class in the extended module if not found in extended_types
410
467
  # iterate over the extended_type Union and check if the class name is in the __dict__
411
468
  if cls is None:
412
- raise ImportError(f"Class {request.class_name} not found in extended types")
469
+ msg = f"Class {request.class_name} not found in extended types"
470
+ UserMessage(msg)
471
+ raise ImportError(msg)
413
472
  # Initialize the class with provided init_args and init_kwargs
414
473
  instance = cls(*request.init_args, **request.init_kwargs)
415
474
  # Call the 'forward' or similar method with provided forward_args and forward_kwargs
@@ -418,20 +477,19 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
418
477
  # Check if the type of the result is within extended types or a primitive that can be serialized directly
419
478
  if isinstance(result, Symbol):
420
479
  return result.json() # Convert to dictionary if it's a complex type
421
- else:
422
- return {"result": result} # Return as is if it's a primitive type
480
+ return {"result": result} # Return as is if it's a primitive type
423
481
  except ImportError as e:
424
- raise HTTPException(status_code=404, detail=f"Module not found: {str(e)}")
482
+ raise HTTPException(status_code=404, detail=f"Module not found: {e!s}") from e
425
483
  except AttributeError as e:
426
- raise HTTPException(status_code=404, detail=str(e))
484
+ raise HTTPException(status_code=404, detail=str(e)) from e
427
485
  except TypeError as e:
428
- raise HTTPException(status_code=422, detail=str(e))
486
+ raise HTTPException(status_code=422, detail=str(e)) from e
429
487
  except Exception as e:
430
- raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")
488
+ raise HTTPException(status_code=500, detail=f"An error occurred: {e!s}") from e
431
489
 
432
490
 
433
491
  @app.get("/extended/{instance_id}/")
434
- def get_extended(instance_id: str, api_key: str = Security(get_api_key)):
492
+ def get_extended(instance_id: str, _api_key: str = Security(get_api_key)):
435
493
  # Retrieve an instance by its ID
436
494
  extended_instance = extended_instance_repository.get(instance_id)
437
495
  if extended_instance is None:
@@ -440,7 +498,9 @@ def get_extended(instance_id: str, api_key: str = Security(get_api_key)):
440
498
 
441
499
 
442
500
  @app.patch("/extended/{instance_id}/")
443
- def update_extended(instance_id: str, update_request: UpdateExtendedRequest, api_key: str = Security(get_api_key)):
501
+ def update_extended(
502
+ instance_id: str, update_request: UpdateExtendedRequest, _api_key: str = Security(get_api_key)
503
+ ):
444
504
  # Retrieve the instance by its ID
445
505
  extended_instance = extended_instance_repository.get(instance_id)
446
506
  if extended_instance is None:
@@ -453,11 +513,13 @@ def update_extended(instance_id: str, update_request: UpdateExtendedRequest, api
453
513
 
454
514
 
455
515
  @app.delete("/extended/{instance_id}/")
456
- def delete_extended(instance_id: str, api_key: str = Security(get_api_key)):
516
+ def delete_extended(instance_id: str, _api_key: str = Security(get_api_key)):
457
517
  # Attempt to delete the instance by its ID
458
518
  success = extended_instance_repository.delete(instance_id)
459
519
  if not success:
460
- raise HTTPException(status_code=404, detail="Extended instance not found or already deleted")
520
+ raise HTTPException(
521
+ status_code=404, detail="Extended instance not found or already deleted"
522
+ )
461
523
  return {"message": "Extended instance deleted successfully"}
462
524
 
463
525
 
Binary file
@@ -1,16 +1,50 @@
1
- from .arxiv_pdf_parser import *
2
- from .conversation import *
3
- from .document import *
4
- from .file_merger import *
5
- from .graph import *
6
- from .html_style_template import *
7
- from .packages import *
8
- from .repo_cloner import *
9
- from .solver import *
10
- from .summarizer import *
11
- from .personas import *
1
+ from importlib import import_module as _import_module
2
+
12
3
  from .api_builder import APIBuilder, APIExecutor
4
+ from .bibtex_parser import BibTexParser
13
5
  from .os_command import OSCommand
14
6
  from .taypan_interpreter import TaypanInterpreter
15
- from .bibtex_parser import BibTexParser
16
7
  from .vectordb import VectorDB
8
+
9
+ __all__ = [
10
+ "APIBuilder",
11
+ "APIExecutor",
12
+ "BibTexParser",
13
+ "OSCommand",
14
+ "TaypanInterpreter",
15
+ "VectorDB",
16
+ ]
17
+
18
+ _seen_names = set(__all__)
19
+
20
+
21
+ def _export_module(module_name: str, seen_names: set[str] = _seen_names) -> None:
22
+ module = _import_module(f"{__name__}.{module_name}")
23
+ public_names = getattr(module, "__all__", None)
24
+ if public_names is None:
25
+ public_names = [name for name in dir(module) if not name.startswith("_")]
26
+ for name in public_names:
27
+ globals()[name] = getattr(module, name)
28
+ if name not in seen_names:
29
+ __all__.append(name)
30
+ seen_names.add(name)
31
+
32
+
33
+ for _module_name in [
34
+ "arxiv_pdf_parser",
35
+ "conversation",
36
+ "document",
37
+ "file_merger",
38
+ "graph",
39
+ "html_style_template",
40
+ "packages",
41
+ "repo_cloner",
42
+ "solver",
43
+ "summarizer",
44
+ ]:
45
+ _export_module(_module_name)
46
+
47
+
48
+ del _export_module
49
+ del _module_name
50
+ del _seen_names