symbolicai 0.20.2__py3-none-any.whl → 1.0.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 (123) hide show
  1. symai/__init__.py +96 -64
  2. symai/backend/base.py +93 -80
  3. symai/backend/engines/drawing/engine_bfl.py +12 -11
  4. symai/backend/engines/drawing/engine_gpt_image.py +108 -87
  5. symai/backend/engines/embedding/engine_llama_cpp.py +25 -28
  6. symai/backend/engines/embedding/engine_openai.py +3 -5
  7. symai/backend/engines/execute/engine_python.py +6 -5
  8. symai/backend/engines/files/engine_io.py +74 -67
  9. symai/backend/engines/imagecaptioning/engine_blip2.py +3 -3
  10. symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +54 -38
  11. symai/backend/engines/index/engine_pinecone.py +23 -24
  12. symai/backend/engines/index/engine_vectordb.py +16 -14
  13. symai/backend/engines/lean/engine_lean4.py +38 -34
  14. symai/backend/engines/neurosymbolic/__init__.py +41 -13
  15. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +262 -182
  16. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +263 -191
  17. symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +53 -49
  18. symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +212 -211
  19. symai/backend/engines/neurosymbolic/engine_groq.py +87 -63
  20. symai/backend/engines/neurosymbolic/engine_huggingface.py +21 -24
  21. symai/backend/engines/neurosymbolic/engine_llama_cpp.py +117 -48
  22. symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +256 -229
  23. symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +270 -150
  24. symai/backend/engines/ocr/engine_apilayer.py +6 -8
  25. symai/backend/engines/output/engine_stdout.py +1 -4
  26. symai/backend/engines/search/engine_openai.py +7 -7
  27. symai/backend/engines/search/engine_perplexity.py +5 -5
  28. symai/backend/engines/search/engine_serpapi.py +12 -14
  29. symai/backend/engines/speech_to_text/engine_local_whisper.py +20 -27
  30. symai/backend/engines/symbolic/engine_wolframalpha.py +3 -3
  31. symai/backend/engines/text_to_speech/engine_openai.py +5 -7
  32. symai/backend/engines/text_vision/engine_clip.py +7 -11
  33. symai/backend/engines/userinput/engine_console.py +3 -3
  34. symai/backend/engines/webscraping/engine_requests.py +81 -48
  35. symai/backend/mixin/__init__.py +13 -0
  36. symai/backend/mixin/anthropic.py +4 -2
  37. symai/backend/mixin/deepseek.py +2 -0
  38. symai/backend/mixin/google.py +2 -0
  39. symai/backend/mixin/openai.py +11 -3
  40. symai/backend/settings.py +83 -16
  41. symai/chat.py +101 -78
  42. symai/collect/__init__.py +7 -1
  43. symai/collect/dynamic.py +77 -69
  44. symai/collect/pipeline.py +35 -27
  45. symai/collect/stats.py +75 -63
  46. symai/components.py +198 -169
  47. symai/constraints.py +15 -12
  48. symai/core.py +698 -359
  49. symai/core_ext.py +32 -34
  50. symai/endpoints/api.py +80 -73
  51. symai/extended/.DS_Store +0 -0
  52. symai/extended/__init__.py +46 -12
  53. symai/extended/api_builder.py +11 -8
  54. symai/extended/arxiv_pdf_parser.py +13 -12
  55. symai/extended/bibtex_parser.py +2 -3
  56. symai/extended/conversation.py +101 -90
  57. symai/extended/document.py +17 -10
  58. symai/extended/file_merger.py +18 -13
  59. symai/extended/graph.py +18 -13
  60. symai/extended/html_style_template.py +2 -4
  61. symai/extended/interfaces/blip_2.py +1 -2
  62. symai/extended/interfaces/clip.py +1 -2
  63. symai/extended/interfaces/console.py +7 -1
  64. symai/extended/interfaces/dall_e.py +1 -1
  65. symai/extended/interfaces/flux.py +1 -1
  66. symai/extended/interfaces/gpt_image.py +1 -1
  67. symai/extended/interfaces/input.py +1 -1
  68. symai/extended/interfaces/llava.py +0 -1
  69. symai/extended/interfaces/naive_vectordb.py +7 -8
  70. symai/extended/interfaces/naive_webscraping.py +1 -1
  71. symai/extended/interfaces/ocr.py +1 -1
  72. symai/extended/interfaces/pinecone.py +6 -5
  73. symai/extended/interfaces/serpapi.py +1 -1
  74. symai/extended/interfaces/terminal.py +2 -3
  75. symai/extended/interfaces/tts.py +1 -1
  76. symai/extended/interfaces/whisper.py +1 -1
  77. symai/extended/interfaces/wolframalpha.py +1 -1
  78. symai/extended/metrics/__init__.py +11 -1
  79. symai/extended/metrics/similarity.py +11 -13
  80. symai/extended/os_command.py +17 -16
  81. symai/extended/packages/__init__.py +29 -3
  82. symai/extended/packages/symdev.py +19 -16
  83. symai/extended/packages/sympkg.py +12 -9
  84. symai/extended/packages/symrun.py +21 -19
  85. symai/extended/repo_cloner.py +11 -10
  86. symai/extended/seo_query_optimizer.py +1 -2
  87. symai/extended/solver.py +20 -23
  88. symai/extended/summarizer.py +4 -3
  89. symai/extended/taypan_interpreter.py +10 -12
  90. symai/extended/vectordb.py +99 -82
  91. symai/formatter/__init__.py +9 -1
  92. symai/formatter/formatter.py +12 -16
  93. symai/formatter/regex.py +62 -63
  94. symai/functional.py +176 -122
  95. symai/imports.py +136 -127
  96. symai/interfaces.py +56 -27
  97. symai/memory.py +14 -13
  98. symai/misc/console.py +49 -39
  99. symai/misc/loader.py +5 -3
  100. symai/models/__init__.py +17 -1
  101. symai/models/base.py +269 -181
  102. symai/models/errors.py +0 -1
  103. symai/ops/__init__.py +32 -22
  104. symai/ops/measures.py +11 -15
  105. symai/ops/primitives.py +348 -228
  106. symai/post_processors.py +32 -28
  107. symai/pre_processors.py +39 -41
  108. symai/processor.py +6 -4
  109. symai/prompts.py +59 -45
  110. symai/server/huggingface_server.py +23 -20
  111. symai/server/llama_cpp_server.py +7 -5
  112. symai/shell.py +3 -4
  113. symai/shellsv.py +499 -375
  114. symai/strategy.py +517 -287
  115. symai/symbol.py +111 -116
  116. symai/utils.py +42 -36
  117. {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/METADATA +4 -2
  118. symbolicai-1.0.0.dist-info/RECORD +163 -0
  119. symbolicai-0.20.2.dist-info/RECORD +0 -162
  120. {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/WHEEL +0 -0
  121. {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/entry_points.txt +0 -0
  122. {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/licenses/LICENSE +0 -0
  123. {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/top_level.txt +0 -0
symai/core_ext.py CHANGED
@@ -3,22 +3,20 @@ import atexit
3
3
  import functools
4
4
  import logging
5
5
  import multiprocessing as mp
6
- import os
7
6
  import pickle
8
7
  import random
9
- import sys
10
- import time
11
8
  import threading
9
+ import time
12
10
  import traceback
11
+ from collections.abc import Callable
13
12
  from pathlib import Path
14
- from typing import Callable, List
15
13
 
16
14
  import dill
17
15
  from loguru import logger
18
- from pathos.multiprocessing import ProcessingPool as PPool
19
16
 
20
17
  from . import __root_dir__
21
18
  from .functional import EngineRepository
19
+ from .utils import UserMessage
22
20
 
23
21
  logging.getLogger("multiprocessing").setLevel(logging.ERROR)
24
22
 
@@ -50,7 +48,7 @@ def _run_in_process(expr, func, args, kwargs):
50
48
  func = dill.loads(func)
51
49
  return func(expr, *args, **kwargs)
52
50
 
53
- def _parallel(func: Callable, expressions: List[Callable], worker: int = mp.cpu_count() // 2):
51
+ def _parallel(func: Callable, expressions: list[Callable], worker: int = mp.cpu_count() // 2):
54
52
  pickled_exprs = [dill.dumps(expr) for expr in expressions]
55
53
  pickled_func = dill.dumps(func)
56
54
  pool = _get_pool(worker)
@@ -62,15 +60,14 @@ def _parallel(func: Callable, expressions: List[Callable], worker: int = mp.cpu_
62
60
  return proxy_function
63
61
 
64
62
  # Decorator
65
- def parallel(expressions: List[Callable], worker: int = mp.cpu_count() // 2):
63
+ def parallel(expressions: list[Callable], worker: int = mp.cpu_count() // 2):
66
64
  def decorator_parallel(func):
67
65
  @functools.wraps(func)
68
66
  def wrapper(*args, **kwargs):
69
67
  # Run expressions in parallel
70
68
  parallel_func = _parallel(func, expressions, worker=worker)
71
69
  # Call the proxy function to execute in parallel and capture results
72
- results = parallel_func(*args, **kwargs)
73
- return results
70
+ return parallel_func(*args, **kwargs)
74
71
  return wrapper
75
72
  return decorator_parallel
76
73
 
@@ -80,7 +77,7 @@ def bind(engine: str, property: str):
80
77
  '''
81
78
  def decorator(func):
82
79
  @functools.wraps(func)
83
- def wrapper(*args, **kwargs):
80
+ def wrapper(*_args, **_kwargs):
84
81
  return EngineRepository.bind_property(
85
82
  engine=engine,
86
83
  property=property
@@ -127,20 +124,19 @@ def retry(
127
124
  graceful=graceful
128
125
  )
129
126
  return async_wrapper
130
- else:
131
- @functools.wraps(func)
132
- def sync_wrapper(*args, **kwargs):
133
- return _retry_func(
134
- functools.partial(func, *args, **kwargs),
135
- exceptions=exceptions,
136
- tries=tries,
137
- delay=delay,
138
- max_delay=max_delay,
139
- backoff=backoff,
140
- jitter=jitter,
141
- graceful=graceful
142
- )
143
- return sync_wrapper
127
+ @functools.wraps(func)
128
+ def sync_wrapper(*args, **kwargs):
129
+ return _retry_func(
130
+ functools.partial(func, *args, **kwargs),
131
+ exceptions=exceptions,
132
+ tries=tries,
133
+ delay=delay,
134
+ max_delay=max_delay,
135
+ backoff=backoff,
136
+ jitter=jitter,
137
+ graceful=graceful
138
+ )
139
+ return sync_wrapper
144
140
  return decorator
145
141
 
146
142
 
@@ -158,7 +154,7 @@ def _retry_func(
158
154
  while _tries:
159
155
  try:
160
156
  return func()
161
- except exceptions as e:
157
+ except exceptions:
162
158
  _tries -= 1
163
159
  if not _tries:
164
160
  if graceful:
@@ -175,6 +171,7 @@ def _retry_func(
175
171
 
176
172
  if max_delay >= 0:
177
173
  _delay = min(_delay, max_delay)
174
+ return None
178
175
 
179
176
 
180
177
  async def _aretry_func(
@@ -191,7 +188,7 @@ async def _aretry_func(
191
188
  while _tries:
192
189
  try:
193
190
  return await func()
194
- except exceptions as e:
191
+ except exceptions:
195
192
  _tries -= 1
196
193
  if not _tries:
197
194
  if graceful:
@@ -208,6 +205,7 @@ async def _aretry_func(
208
205
 
209
206
  if max_delay >= 0:
210
207
  _delay = min(_delay, max_delay)
208
+ return None
211
209
 
212
210
 
213
211
  def cache(
@@ -237,16 +235,16 @@ def _cache_registry_func(
237
235
  *args, **kwargs
238
236
  ):
239
237
 
240
- if not os.path.exists(cache_path): os.makedirs(cache_path)
241
-
242
- if in_memory and os.path.exists(Path(cache_path) / func.__qualname__):
243
- with open(Path(cache_path) / func.__qualname__, 'rb') as f:
244
- call = pickle.load(f)
238
+ cache_dir = Path(cache_path)
239
+ cache_dir.mkdir(parents=True, exist_ok=True)
240
+ cache_file = cache_dir / func.__qualname__
245
241
 
246
- return call
242
+ if in_memory and cache_file.exists():
243
+ with cache_file.open('rb') as f:
244
+ return pickle.load(f)
247
245
 
248
246
  call = func(*args, **kwargs)
249
- with open(Path(cache_path) / func.__qualname__, 'wb') as f:
247
+ with cache_file.open('wb') as f:
250
248
  pickle.dump(call , f)
251
249
 
252
250
  return call
@@ -265,7 +263,7 @@ def error_logging(debug: bool = False):
265
263
  logger.error(e)
266
264
  if debug:
267
265
  # Simple message:
268
- print('Function: {} call failed. Error: {}'.format(func.__name__, e))
266
+ UserMessage(f'Function: {func.__name__} call failed. Error: {e}')
269
267
  # print traceback
270
268
  traceback.print_exc()
271
269
  raise e
symai/endpoints/api.py CHANGED
@@ -1,20 +1,20 @@
1
1
  import importlib
2
2
  import inspect
3
3
  import pickle
4
- import redis
4
+ from typing import Any
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
20
  HOST = 'localhost'
@@ -27,20 +27,16 @@ def is_redis_running(host: str, port: int) -> bool:
27
27
  try:
28
28
  r = redis.Redis(host=host, port=port)
29
29
  r.ping()
30
- print(f"Redis server is running at {host}:{port}")
30
+ UserMessage(f"Redis server is running at {host}:{port}")
31
31
  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")
32
+ except RedisConnectionError:
33
+ UserMessage(f"Redis server is not running at {host}:{port} or is not reachable - falling back to in-memory storage")
34
34
  return False
35
35
 
36
36
 
37
- # Create a generic type variable
38
- T = TypeVar('T')
39
-
40
-
41
- class GenericRepository(Generic[T]):
37
+ class GenericRepository[T]:
42
38
  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
39
+ self.storage: dict[str, T] = {} # In-memory dictionary to mock Redis
44
40
  self.use_redis = use_redis
45
41
  self.id_key = id_key # Key used for storing the incremental ID counter
46
42
  self.redis_client = redis_client
@@ -59,7 +55,7 @@ class GenericRepository(Generic[T]):
59
55
  """Deserialize the byte object back into a Python object of type T."""
60
56
  return pickle.loads(serialized_item)
61
57
 
62
- def _serialize_object(self, item_id: str, item: T) -> None:
58
+ def _serialize_object(self, _item_id: str, item: T) -> None:
63
59
  return pickle.dumps(item)
64
60
 
65
61
  def _store_memory(self, item_id: str, item: T) -> None:
@@ -85,8 +81,7 @@ class GenericRepository(Generic[T]):
85
81
  def _retrieve_redis(self, item_id: str) -> T:
86
82
  item = self.redis_client.get(item_id)
87
83
  if item:
88
- item = self._deserialize_object(item)
89
- return item
84
+ return self._deserialize_object(item)
90
85
  return None
91
86
 
92
87
  def _delete_redis(self, item_id: str) -> bool:
@@ -117,7 +112,22 @@ expression_repository = GenericRepository[Expression](redis_client, "exp
117
112
  component_class_types = {
118
113
  name: cls for name, cls in inspect.getmembers(importlib.import_module('symai.components'), inspect.isclass) if issubclass(cls, Expression)
119
114
  }
120
- component_instance_repository = GenericRepository[Union[Symbol, Expression]](redis_client, "comp_id", use_redis=use_redis)
115
+ component_instance_repository = GenericRepository[Symbol | Expression](redis_client, "comp_id", use_redis=use_redis)
116
+
117
+
118
+ def _load_extended_types():
119
+ """Load extended classes lazily to avoid premature engine initialization."""
120
+ extended_module = importlib.import_module('symai.extended')
121
+ personas_module = importlib.import_module('symai.extended.personas')
122
+ sales_module = importlib.import_module('symai.extended.personas.sales')
123
+ student_module = importlib.import_module('symai.extended.personas.student')
124
+ return [
125
+ extended_module.Conversation,
126
+ personas_module.Persona,
127
+ personas_module.Dialogue,
128
+ student_module.MaxTenner,
129
+ sales_module.ErikJames,
130
+ ]
121
131
 
122
132
  app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
123
133
 
@@ -125,8 +135,8 @@ app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True,
125
135
 
126
136
 
127
137
  class CreateSymbolRequest(BaseModel):
128
- value: Optional[Any] = None
129
- static_context: Optional[str] = ''
138
+ value: Any | None = None
139
+ static_context: str | None = ''
130
140
 
131
141
 
132
142
  class UpdateSymbolRequest(BaseModel):
@@ -135,11 +145,11 @@ class UpdateSymbolRequest(BaseModel):
135
145
 
136
146
 
137
147
  class SymbolMethodRequest(BaseModel):
138
- args: List[Any] = []
139
- kwargs: Dict[str, Any] = {}
148
+ args: list[Any] = []
149
+ kwargs: dict[str, Any] = {}
140
150
 
141
151
  def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else None) -> str:
142
- if API_KEY == None:
152
+ if API_KEY is None:
143
153
  return True
144
154
  if api_key_header == API_KEY:
145
155
  return api_key_header
@@ -149,7 +159,7 @@ def get_api_key(api_key_header: str = Security(api_key_header) if API_KEY else N
149
159
  )
150
160
 
151
161
  @app.post("/symbol/")
152
- def create_symbol(symbol_request: CreateSymbolRequest, api_key: str = Security(get_api_key)):
162
+ def create_symbol(symbol_request: CreateSymbolRequest, _api_key: str = Security(get_api_key)):
153
163
  symbol = Symbol(symbol_request.value, static_context=symbol_request.static_context)
154
164
  symbol_id = symbol_repository.uid()
155
165
  symbol_repository.set(symbol_id, symbol)
@@ -157,7 +167,7 @@ def create_symbol(symbol_request: CreateSymbolRequest, api_key: str = Security(g
157
167
 
158
168
 
159
169
  @app.get("/symbol/{symbol_id}/")
160
- def get_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
170
+ def get_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
161
171
  symbol = symbol_repository.get(symbol_id)
162
172
  if symbol is None:
163
173
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -165,7 +175,7 @@ def get_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
165
175
 
166
176
 
167
177
  @app.patch("/symbol/{symbol_id}/")
168
- def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, api_key: str = Security(get_api_key)):
178
+ def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, _api_key: str = Security(get_api_key)):
169
179
  symbol = symbol_repository.get(symbol_id)
170
180
  if symbol is None:
171
181
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -176,7 +186,7 @@ def update_symbol(symbol_id: str, update_request: UpdateSymbolRequest, api_key:
176
186
 
177
187
 
178
188
  @app.delete("/symbol/{symbol_id}/")
179
- def delete_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
189
+ def delete_symbol(symbol_id: str, _api_key: str = Security(get_api_key)):
180
190
  symbol = symbol_repository.delete(symbol_id)
181
191
  if symbol is None:
182
192
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -185,7 +195,7 @@ def delete_symbol(symbol_id: str, api_key: str = Security(get_api_key)):
185
195
 
186
196
  @app.post("/symbol/{symbol_id}/{method_name}/")
187
197
  @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)):
198
+ def operate_on_symbol(symbol_id: str, method_name: str, method_request: SymbolMethodRequest, _api_key: str = Security(get_api_key)):
189
199
  symbol = symbol_repository.get(symbol_id)
190
200
  if symbol is None:
191
201
  raise HTTPException(status_code=404, detail="Symbol not found")
@@ -200,7 +210,7 @@ def operate_on_symbol(symbol_id: str, method_name: str, method_request: SymbolMe
200
210
 
201
211
 
202
212
  class CreateExpressionRequest(BaseModel):
203
- value: Optional[Any] = None
213
+ value: Any | None = None
204
214
 
205
215
 
206
216
  class UpdateExpressionRequest(BaseModel):
@@ -208,7 +218,7 @@ class UpdateExpressionRequest(BaseModel):
208
218
 
209
219
 
210
220
  @app.post("/expression/")
211
- def create_expression(expression_request: CreateExpressionRequest, api_key: str = Security(get_api_key)):
221
+ def create_expression(expression_request: CreateExpressionRequest, _api_key: str = Security(get_api_key)):
212
222
  expression = Expression(expression_request.value)
213
223
  expression_id = expression_repository.uid()
214
224
  expression_repository.set(expression_id, expression)
@@ -216,7 +226,7 @@ def create_expression(expression_request: CreateExpressionRequest, api_key: str
216
226
 
217
227
 
218
228
  @app.get("/expression/{expression_id}/")
219
- def get_expression(expression_id: str, api_key: str = Security(get_api_key)):
229
+ def get_expression(expression_id: str, _api_key: str = Security(get_api_key)):
220
230
  expression = expression_repository.get(expression_id)
221
231
  if expression is None:
222
232
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -225,7 +235,7 @@ def get_expression(expression_id: str, api_key: str = Security(get_api_key)):
225
235
 
226
236
  @app.post("/expression/{expression_id}/call/")
227
237
  @core_ext.error_logging(debug=DEBUG)
228
- def call_expression(expression_id: str, method_request: SymbolMethodRequest, api_key: str = Security(get_api_key)):
238
+ def call_expression(expression_id: str, method_request: SymbolMethodRequest, _api_key: str = Security(get_api_key)):
229
239
  # Retrieve the expression instance by ID
230
240
  expression = expression_repository.get(expression_id)
231
241
  if expression is None:
@@ -236,7 +246,7 @@ def call_expression(expression_id: str, method_request: SymbolMethodRequest, api
236
246
 
237
247
  @app.post("/expression/{expression_id}/{method_name}/")
238
248
  @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)):
249
+ def operate_on_expression(expression_id: str, method_name: str, method_request: SymbolMethodRequest, _api_key: str = Security(get_api_key)):
240
250
  expression = expression_repository.get(expression_id)
241
251
  if expression is None:
242
252
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -248,7 +258,7 @@ def operate_on_expression(expression_id: str, method_name: str, method_request:
248
258
 
249
259
 
250
260
  @app.patch("/expression/{expression_id}/")
251
- def update_expression(expression_id: str, update_request: UpdateExpressionRequest, api_key: str = Security(get_api_key)):
261
+ def update_expression(expression_id: str, update_request: UpdateExpressionRequest, _api_key: str = Security(get_api_key)):
252
262
  expression = expression_repository.get(expression_id)
253
263
  if expression is None:
254
264
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -259,7 +269,7 @@ def update_expression(expression_id: str, update_request: UpdateExpressionReques
259
269
 
260
270
 
261
271
  @app.delete("/expression/{expression_id}/")
262
- def delete_expression(expression_id: str, api_key: str = Security(get_api_key)):
272
+ def delete_expression(expression_id: str, _api_key: str = Security(get_api_key)):
263
273
  expression = expression_repository.delete(expression_id)
264
274
  if expression is None:
265
275
  raise HTTPException(status_code=404, detail="Expression not found")
@@ -278,25 +288,25 @@ class AddComponentRequest(BaseModel):
278
288
  # Endpoint to instantiate a generic component class and get the ID
279
289
  class CreateComponentGenericRequest(BaseModel):
280
290
  class_name: str
281
- init_args: List[Any] = []
282
- init_kwargs: Dict[str, Any] = {}
291
+ init_args: list[Any] = []
292
+ init_kwargs: dict[str, Any] = {}
283
293
 
284
294
 
285
295
  # Modify the existing GenericRequest
286
296
  class GenericRequest(BaseModel):
287
297
  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] = {}
298
+ init_args: list[Any] = {}
299
+ init_kwargs: dict[str, Any] = {}
300
+ forward_args: list[ Any] = {}
301
+ forward_kwargs: dict[str, Any] = {}
292
302
 
293
303
 
294
304
  class UpdateComponentRequest(BaseModel):
295
- update_kwargs: Dict[str, Any] = {}
305
+ update_kwargs: dict[str, Any] = {}
296
306
 
297
307
 
298
308
  @app.post("/components/")
299
- def create_component(request: CreateComponentGenericRequest, api_key: str = Security(get_api_key)):
309
+ def create_component(request: CreateComponentGenericRequest, _api_key: str = Security(get_api_key)):
300
310
  # Retrieve the class from the repository
301
311
  cls = component_class_types.get(request.class_name)
302
312
  if cls is None:
@@ -310,7 +320,7 @@ def create_component(request: CreateComponentGenericRequest, api_key: str = Secu
310
320
 
311
321
 
312
322
  @app.get("/components/{instance_id}/")
313
- def get_component(instance_id: str, api_key: str = Security(get_api_key)):
323
+ def get_component(instance_id: str, _api_key: str = Security(get_api_key)):
314
324
  # Retrieve an instance by its ID from the repository
315
325
  instance = component_instance_repository.get(instance_id)
316
326
  if instance is None:
@@ -321,13 +331,15 @@ def get_component(instance_id: str, api_key: str = Security(get_api_key)):
321
331
  # Endpoint to execute a command on a component instance
322
332
  @app.post("/components/call/")
323
333
  @core_ext.error_logging(debug=DEBUG)
324
- def generic_forward(request: GenericRequest, api_key: str = Security(get_api_key)):
334
+ def generic_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
325
335
  # Dynamically import the class from components module based on request.class_name
326
336
  components_module = importlib.import_module('.components', package='symai')
327
337
  cls = getattr(components_module, request.class_name)
328
338
  # Check if cls is subclass of Expression and instantiate
329
339
  if not issubclass(cls, components_module.Expression):
330
- raise ValueError("The provided class name must be a subclass of Expression")
340
+ msg = "The provided class name must be a subclass of Expression"
341
+ UserMessage(msg)
342
+ raise ValueError(msg)
331
343
  # Initialize the class with provided init_args, requiring unpacking **kwargs
332
344
  instance = cls(*request.init_args, **request.init_kwargs)
333
345
  # Call the forward method with provided forward_args, requiring unpacking **kwargs
@@ -339,7 +351,7 @@ def generic_forward(request: GenericRequest, api_key: str = Security(get_api_key
339
351
 
340
352
 
341
353
  @app.patch("/components/{instance_id}/")
342
- def update_component(instance_id: str, update_request: UpdateComponentRequest, api_key: str = Security(get_api_key)):
354
+ def update_component(instance_id: str, update_request: UpdateComponentRequest, _api_key: str = Security(get_api_key)):
343
355
  instance = component_instance_repository.get(instance_id)
344
356
  if instance is None:
345
357
  raise HTTPException(status_code=404, detail="Component instance not found")
@@ -350,7 +362,7 @@ def update_component(instance_id: str, update_request: UpdateComponentRequest, a
350
362
 
351
363
 
352
364
  @app.delete("/components/{instance_id}/")
353
- def delete_component(instance_id: str, api_key: str = Security(get_api_key)):
365
+ def delete_component(instance_id: str, _api_key: str = Security(get_api_key)):
354
366
  instance = component_instance_repository.delete(instance_id)
355
367
  if instance is None:
356
368
  raise HTTPException(status_code=404, detail="Component instance not found")
@@ -359,14 +371,8 @@ def delete_component(instance_id: str, api_key: str = Security(get_api_key)):
359
371
 
360
372
  ### Selectively register the endpoints with the API router ###
361
373
 
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]
374
+ # extended types loaded lazily to avoid early engine configuration
375
+ extended_types = _load_extended_types()
370
376
  # Register only the extended types from the extended_types Union
371
377
  extended_class_types = {c.__name__: c for c in extended_types}
372
378
  extended_instance_repository = GenericRepository[extended_types](redis_client, "ext_id", use_redis=use_redis)
@@ -375,17 +381,17 @@ extended_instance_repository = GenericRepository[extended_types](redis_client, "
375
381
  # Model definitions for extended classes
376
382
  class CreateExtendedRequest(BaseModel):
377
383
  class_name: str
378
- init_args: List[Any] = []
379
- init_kwargs: Dict[str, Any] = {}
384
+ init_args: list[Any] = []
385
+ init_kwargs: dict[str, Any] = {}
380
386
 
381
387
 
382
388
  class UpdateExtendedRequest(BaseModel):
383
- update_kwargs: Dict[str, Any] = {}
389
+ update_kwargs: dict[str, Any] = {}
384
390
 
385
391
 
386
392
  # Create endpoints for each of the extended classes
387
393
  @app.post("/extended/")
388
- def create_extended(request: CreateExtendedRequest, api_key: str = Security(get_api_key)):
394
+ def create_extended(request: CreateExtendedRequest, _api_key: str = Security(get_api_key)):
389
395
  # Dynamically retrieve the extended class
390
396
  extended_class = extended_class_types.get(request.class_name)
391
397
  if extended_class is None:
@@ -401,7 +407,7 @@ def create_extended(request: CreateExtendedRequest, api_key: str = Security(get_
401
407
  # Endpoint to execute a command on a component instance
402
408
  @app.post("/extended/call/")
403
409
  @core_ext.error_logging(debug=DEBUG)
404
- def extended_forward(request: GenericRequest, api_key: str = Security(get_api_key)):
410
+ def extended_forward(request: GenericRequest, _api_key: str = Security(get_api_key)):
405
411
  # Dynamically import the class from components module based on request.class_name
406
412
  try:
407
413
  # get request.class_name from extended_types if it's a type of extended_types
@@ -409,7 +415,9 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
409
415
  # look for the class in the extended module if not found in extended_types
410
416
  # iterate over the extended_type Union and check if the class name is in the __dict__
411
417
  if cls is None:
412
- raise ImportError(f"Class {request.class_name} not found in extended types")
418
+ msg = f"Class {request.class_name} not found in extended types"
419
+ UserMessage(msg)
420
+ raise ImportError(msg)
413
421
  # Initialize the class with provided init_args and init_kwargs
414
422
  instance = cls(*request.init_args, **request.init_kwargs)
415
423
  # Call the 'forward' or similar method with provided forward_args and forward_kwargs
@@ -418,20 +426,19 @@ def extended_forward(request: GenericRequest, api_key: str = Security(get_api_ke
418
426
  # Check if the type of the result is within extended types or a primitive that can be serialized directly
419
427
  if isinstance(result, Symbol):
420
428
  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
429
+ return {"result": result} # Return as is if it's a primitive type
423
430
  except ImportError as e:
424
- raise HTTPException(status_code=404, detail=f"Module not found: {str(e)}")
431
+ raise HTTPException(status_code=404, detail=f"Module not found: {e!s}") from e
425
432
  except AttributeError as e:
426
- raise HTTPException(status_code=404, detail=str(e))
433
+ raise HTTPException(status_code=404, detail=str(e)) from e
427
434
  except TypeError as e:
428
- raise HTTPException(status_code=422, detail=str(e))
435
+ raise HTTPException(status_code=422, detail=str(e)) from e
429
436
  except Exception as e:
430
- raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")
437
+ raise HTTPException(status_code=500, detail=f"An error occurred: {e!s}") from e
431
438
 
432
439
 
433
440
  @app.get("/extended/{instance_id}/")
434
- def get_extended(instance_id: str, api_key: str = Security(get_api_key)):
441
+ def get_extended(instance_id: str, _api_key: str = Security(get_api_key)):
435
442
  # Retrieve an instance by its ID
436
443
  extended_instance = extended_instance_repository.get(instance_id)
437
444
  if extended_instance is None:
@@ -440,7 +447,7 @@ def get_extended(instance_id: str, api_key: str = Security(get_api_key)):
440
447
 
441
448
 
442
449
  @app.patch("/extended/{instance_id}/")
443
- def update_extended(instance_id: str, update_request: UpdateExtendedRequest, api_key: str = Security(get_api_key)):
450
+ def update_extended(instance_id: str, update_request: UpdateExtendedRequest, _api_key: str = Security(get_api_key)):
444
451
  # Retrieve the instance by its ID
445
452
  extended_instance = extended_instance_repository.get(instance_id)
446
453
  if extended_instance is None:
@@ -453,7 +460,7 @@ def update_extended(instance_id: str, update_request: UpdateExtendedRequest, api
453
460
 
454
461
 
455
462
  @app.delete("/extended/{instance_id}/")
456
- def delete_extended(instance_id: str, api_key: str = Security(get_api_key)):
463
+ def delete_extended(instance_id: str, _api_key: str = Security(get_api_key)):
457
464
  # Attempt to delete the instance by its ID
458
465
  success = extended_instance_repository.delete(instance_id)
459
466
  if not success:
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
@@ -1,9 +1,9 @@
1
1
  from .. import core
2
- from ..pre_processors import PreProcessor
2
+ from ..components import Execute
3
3
  from ..post_processors import CodeExtractPostProcessor
4
+ from ..pre_processors import PreProcessor
4
5
  from ..symbol import Expression, Symbol
5
- from ..components import Execute
6
-
6
+ from ..utils import UserMessage
7
7
 
8
8
  API_BUILDER_DESCRIPTION = """[Description]
9
9
  You are an API coding tool for Python that creates API calls to any web URL based on user requests.
@@ -64,7 +64,7 @@ res = run(value) # [MANAGED] must contain this line, do not change
64
64
 
65
65
  class APIBuilderPreProcessor(PreProcessor):
66
66
  def __call__(self, argument):
67
- return '$> {} =>'.format(str(argument.args[0]))
67
+ return f'$> {argument.args[0]!s} =>'
68
68
 
69
69
 
70
70
  class APIBuilder(Expression):
@@ -126,14 +126,17 @@ class APIExecutor(Expression):
126
126
  def _runnable(self):
127
127
  return self.executor._runnable
128
128
 
129
- def forward(self, request: Symbol, **kwargs) -> Symbol:
129
+ def forward(self, request: Symbol, **_kwargs) -> Symbol:
130
130
  self._request = self._to_symbol(request)
131
- if self._verbose: print('[REQUEST]', self._request)
131
+ if self._verbose:
132
+ UserMessage(f'[REQUEST] {self._request}')
132
133
  # Generate the code to implement the API call
133
134
  self._code = self.builder(self._request)
134
- if self._verbose: print('[GENERATED_CODE]', self._code)
135
+ if self._verbose:
136
+ UserMessage(f'[GENERATED_CODE] {self._code}')
135
137
  # Execute the code to define the 'run' function
136
138
  self._result = self.executor(self._code, request=self._request)
137
- if self._verbose: print('[RESULT]:', self._result)
139
+ if self._verbose:
140
+ UserMessage(f'[RESULT]: {self._result}')
138
141
  self._value = self._result
139
142
  return self