symbolicai 1.0.0__py3-none-any.whl → 1.1.1__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 (129) hide show
  1. symai/__init__.py +198 -134
  2. symai/backend/base.py +51 -51
  3. symai/backend/engines/drawing/engine_bfl.py +33 -33
  4. symai/backend/engines/drawing/engine_gpt_image.py +4 -10
  5. symai/backend/engines/embedding/engine_llama_cpp.py +50 -35
  6. symai/backend/engines/embedding/engine_openai.py +22 -16
  7. symai/backend/engines/execute/engine_python.py +16 -16
  8. symai/backend/engines/files/engine_io.py +51 -49
  9. symai/backend/engines/imagecaptioning/engine_blip2.py +27 -23
  10. symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +53 -46
  11. symai/backend/engines/index/engine_pinecone.py +116 -88
  12. symai/backend/engines/index/engine_qdrant.py +1011 -0
  13. symai/backend/engines/index/engine_vectordb.py +78 -52
  14. symai/backend/engines/lean/engine_lean4.py +65 -25
  15. symai/backend/engines/neurosymbolic/__init__.py +35 -28
  16. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +137 -135
  17. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +145 -152
  18. symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
  19. symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +75 -49
  20. symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +199 -155
  21. symai/backend/engines/neurosymbolic/engine_groq.py +106 -72
  22. symai/backend/engines/neurosymbolic/engine_huggingface.py +100 -67
  23. symai/backend/engines/neurosymbolic/engine_llama_cpp.py +121 -93
  24. symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +213 -132
  25. symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +180 -137
  26. symai/backend/engines/ocr/engine_apilayer.py +18 -20
  27. symai/backend/engines/output/engine_stdout.py +9 -9
  28. symai/backend/engines/{webscraping → scrape}/engine_requests.py +25 -11
  29. symai/backend/engines/search/engine_openai.py +95 -83
  30. symai/backend/engines/search/engine_parallel.py +665 -0
  31. symai/backend/engines/search/engine_perplexity.py +40 -41
  32. symai/backend/engines/search/engine_serpapi.py +33 -28
  33. symai/backend/engines/speech_to_text/engine_local_whisper.py +37 -27
  34. symai/backend/engines/symbolic/engine_wolframalpha.py +14 -8
  35. symai/backend/engines/text_to_speech/engine_openai.py +15 -19
  36. symai/backend/engines/text_vision/engine_clip.py +34 -28
  37. symai/backend/engines/userinput/engine_console.py +3 -4
  38. symai/backend/mixin/__init__.py +4 -0
  39. symai/backend/mixin/anthropic.py +48 -40
  40. symai/backend/mixin/cerebras.py +9 -0
  41. symai/backend/mixin/deepseek.py +4 -5
  42. symai/backend/mixin/google.py +5 -4
  43. symai/backend/mixin/groq.py +2 -4
  44. symai/backend/mixin/openai.py +132 -110
  45. symai/backend/settings.py +14 -14
  46. symai/chat.py +164 -94
  47. symai/collect/dynamic.py +13 -11
  48. symai/collect/pipeline.py +39 -31
  49. symai/collect/stats.py +109 -69
  50. symai/components.py +578 -238
  51. symai/constraints.py +14 -5
  52. symai/core.py +1495 -1210
  53. symai/core_ext.py +55 -50
  54. symai/endpoints/api.py +113 -58
  55. symai/extended/api_builder.py +22 -17
  56. symai/extended/arxiv_pdf_parser.py +13 -5
  57. symai/extended/bibtex_parser.py +8 -4
  58. symai/extended/conversation.py +88 -69
  59. symai/extended/document.py +40 -27
  60. symai/extended/file_merger.py +45 -7
  61. symai/extended/graph.py +38 -24
  62. symai/extended/html_style_template.py +17 -11
  63. symai/extended/interfaces/blip_2.py +1 -1
  64. symai/extended/interfaces/clip.py +4 -2
  65. symai/extended/interfaces/console.py +5 -3
  66. symai/extended/interfaces/dall_e.py +3 -1
  67. symai/extended/interfaces/file.py +2 -0
  68. symai/extended/interfaces/flux.py +3 -1
  69. symai/extended/interfaces/gpt_image.py +15 -6
  70. symai/extended/interfaces/input.py +2 -1
  71. symai/extended/interfaces/llava.py +1 -1
  72. symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +3 -2
  73. symai/extended/interfaces/naive_vectordb.py +2 -2
  74. symai/extended/interfaces/ocr.py +4 -2
  75. symai/extended/interfaces/openai_search.py +2 -0
  76. symai/extended/interfaces/parallel.py +30 -0
  77. symai/extended/interfaces/perplexity.py +2 -0
  78. symai/extended/interfaces/pinecone.py +6 -4
  79. symai/extended/interfaces/python.py +2 -0
  80. symai/extended/interfaces/serpapi.py +2 -0
  81. symai/extended/interfaces/terminal.py +0 -1
  82. symai/extended/interfaces/tts.py +2 -1
  83. symai/extended/interfaces/whisper.py +2 -1
  84. symai/extended/interfaces/wolframalpha.py +1 -0
  85. symai/extended/metrics/__init__.py +1 -1
  86. symai/extended/metrics/similarity.py +5 -2
  87. symai/extended/os_command.py +31 -22
  88. symai/extended/packages/symdev.py +39 -34
  89. symai/extended/packages/sympkg.py +30 -27
  90. symai/extended/packages/symrun.py +46 -35
  91. symai/extended/repo_cloner.py +10 -9
  92. symai/extended/seo_query_optimizer.py +15 -12
  93. symai/extended/solver.py +104 -76
  94. symai/extended/summarizer.py +8 -7
  95. symai/extended/taypan_interpreter.py +10 -9
  96. symai/extended/vectordb.py +28 -15
  97. symai/formatter/formatter.py +39 -31
  98. symai/formatter/regex.py +46 -44
  99. symai/functional.py +184 -86
  100. symai/imports.py +85 -51
  101. symai/interfaces.py +1 -1
  102. symai/memory.py +33 -24
  103. symai/menu/screen.py +28 -19
  104. symai/misc/console.py +27 -27
  105. symai/misc/loader.py +4 -3
  106. symai/models/base.py +147 -76
  107. symai/models/errors.py +1 -1
  108. symai/ops/__init__.py +1 -1
  109. symai/ops/measures.py +17 -14
  110. symai/ops/primitives.py +933 -635
  111. symai/post_processors.py +28 -24
  112. symai/pre_processors.py +58 -52
  113. symai/processor.py +15 -9
  114. symai/prompts.py +714 -649
  115. symai/server/huggingface_server.py +115 -32
  116. symai/server/llama_cpp_server.py +14 -6
  117. symai/server/qdrant_server.py +206 -0
  118. symai/shell.py +98 -39
  119. symai/shellsv.py +307 -223
  120. symai/strategy.py +135 -81
  121. symai/symbol.py +276 -225
  122. symai/utils.py +62 -46
  123. {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/METADATA +19 -9
  124. symbolicai-1.1.1.dist-info/RECORD +169 -0
  125. symbolicai-1.0.0.dist-info/RECORD +0 -163
  126. {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/WHEEL +0 -0
  127. {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/entry_points.txt +0 -0
  128. {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/licenses/LICENSE +0 -0
  129. {symbolicai-1.0.0.dist-info → symbolicai-1.1.1.dist-info}/top_level.txt +0 -0
symai/imports.py CHANGED
@@ -16,14 +16,16 @@ from .utils import UserMessage
16
16
  logging.getLogger("subprocess").setLevel(logging.ERROR)
17
17
 
18
18
 
19
- __root_dir__ = HOME_PATH / 'packages'
20
- BASE_PACKAGE_MODULE = '' # use relative path
19
+ __root_dir__ = HOME_PATH / "packages"
20
+ BASE_PACKAGE_MODULE = "" # use relative path
21
21
  BASE_PACKAGE_PATH = __root_dir__
22
22
  sys.path.append(str(__root_dir__))
23
23
 
24
24
 
25
25
  class Import(Expression):
26
- def __init__(self, module: str, local_path: str | None = None, submodules: bool = False, *args, **kwargs):
26
+ def __init__(
27
+ self, module: str, local_path: str | None = None, submodules: bool = False, *args, **kwargs
28
+ ):
27
29
  super(self).__init__(*args, **kwargs)
28
30
  self.module = module
29
31
  self.local_path = local_path
@@ -34,8 +36,8 @@ class Import(Expression):
34
36
  # Check if module is a local path or a GitHub repo reference
35
37
  module_path = Path(module)
36
38
  if module_path.exists() and module_path.is_dir():
37
- return (module_path / 'package.json').exists()
38
- return (BASE_PACKAGE_PATH / module / 'package.json').exists()
39
+ return (module_path / "package.json").exists()
40
+ return (BASE_PACKAGE_PATH / module / "package.json").exists()
39
41
 
40
42
  @staticmethod
41
43
  def get_from_local(module, local_path):
@@ -60,25 +62,29 @@ class Import(Expression):
60
62
  logger.info(f"Copied local package from {local_path} to {module_path}")
61
63
 
62
64
  # Install dependencies
63
- package_json = module_path / 'package.json'
65
+ package_json = module_path / "package.json"
64
66
  if package_json.exists():
65
67
  with package_json.open() as f:
66
68
  pkg = json.load(f)
67
- for dependency in pkg.get('dependencies', []):
69
+ for dependency in pkg.get("dependencies", []):
68
70
  # Update git_url for the dependency
69
- git_url_dependency = f'git@github.com:{dependency}.git'
71
+ git_url_dependency = f"git@github.com:{dependency}.git"
70
72
  dependency_path = BASE_PACKAGE_PATH / dependency
71
73
  if not dependency_path.exists():
72
- subprocess.check_call(['git', 'clone', git_url_dependency, str(dependency_path)])
74
+ subprocess.check_call(
75
+ ["git", "clone", git_url_dependency, str(dependency_path)]
76
+ )
73
77
 
74
78
  # Install requirements
75
- requirements_file = module_path / 'requirements.txt'
79
+ requirements_file = module_path / "requirements.txt"
76
80
  if requirements_file.exists():
77
81
  with requirements_file.open() as f:
78
82
  for dependency in f.readlines():
79
83
  dependency_name = dependency.strip()
80
84
  if dependency_name:
81
- subprocess.check_call([sys.executable, '-m', 'pip', 'install', dependency_name])
85
+ subprocess.check_call(
86
+ [sys.executable, "-m", "pip", "install", dependency_name]
87
+ )
82
88
  except Exception as e:
83
89
  logger.error(f"Error installing from local path: {e}")
84
90
  raise
@@ -89,30 +95,32 @@ class Import(Expression):
89
95
  BASE_PACKAGE_PATH.mkdir(parents=True, exist_ok=True)
90
96
 
91
97
  # Clone repository
92
- git_url = f'git@github.com:{module}.git'
93
- clone_cmd = ['git', 'clone']
98
+ git_url = f"git@github.com:{module}.git"
99
+ clone_cmd = ["git", "clone"]
94
100
  if submodules:
95
- clone_cmd.extend(['--recurse-submodules'])
101
+ clone_cmd.extend(["--recurse-submodules"])
96
102
  clone_cmd.extend([git_url, str(BASE_PACKAGE_PATH / module)])
97
103
  subprocess.check_call(clone_cmd)
98
104
 
99
105
  # Install dependencies
100
- package_json = BASE_PACKAGE_PATH / module / 'package.json'
106
+ package_json = BASE_PACKAGE_PATH / module / "package.json"
101
107
  with package_json.open() as f:
102
108
  pkg = json.load(f)
103
- for dependency in pkg['dependencies']:
109
+ for dependency in pkg["dependencies"]:
104
110
  # Update git_url for the dependency
105
- git_url_dependency = f'git@github.com:{dependency}.git'
111
+ git_url_dependency = f"git@github.com:{dependency}.git"
106
112
  dependency_path = BASE_PACKAGE_PATH / dependency
107
113
  if not dependency_path.exists():
108
- subprocess.check_call(['git', 'clone', git_url_dependency, str(dependency_path)])
114
+ subprocess.check_call(
115
+ ["git", "clone", git_url_dependency, str(dependency_path)]
116
+ )
109
117
 
110
118
  # Install requirements
111
- requirements_file = BASE_PACKAGE_PATH / module / 'requirements.txt'
119
+ requirements_file = BASE_PACKAGE_PATH / module / "requirements.txt"
112
120
  if requirements_file.exists():
113
121
  with requirements_file.open() as f:
114
122
  for dependency in f.readlines():
115
- subprocess.check_call(['pip', 'install', dependency])
123
+ subprocess.check_call(["pip", "install", dependency])
116
124
 
117
125
  @staticmethod
118
126
  def load_module_class(module):
@@ -123,9 +131,9 @@ class Import(Expression):
123
131
 
124
132
  package_path = module_path_obj if is_local_path else BASE_PACKAGE_PATH / module
125
133
 
126
- with (package_path / 'package.json').open() as f:
134
+ with (package_path / "package.json").open() as f:
127
135
  pkg = json.load(f)
128
- for expr in pkg['expressions']:
136
+ for expr in pkg["expressions"]:
129
137
  if is_local_path:
130
138
  # For local modules, we need to add the path to sys.path
131
139
  parent_dir = package_path.parent
@@ -135,11 +143,15 @@ class Import(Expression):
135
143
  module_name = package_path.name
136
144
  relative_module_path = f"{module_name}.{expr['module'].replace('/', '.')}"
137
145
  else:
138
- module_parts = module.split('/')
139
- relative_module_path = '.'.join([*module_parts, expr['module'].replace('/', '.')])
146
+ module_parts = module.split("/")
147
+ relative_module_path = ".".join(
148
+ [*module_parts, expr["module"].replace("/", ".")]
149
+ )
140
150
 
141
151
  try:
142
- module_class = getattr(importlib.import_module(relative_module_path), expr['type'])
152
+ module_class = getattr(
153
+ importlib.import_module(relative_module_path), expr["type"]
154
+ )
143
155
  module_classes.append(module_class)
144
156
  except (ImportError, ModuleNotFoundError) as e:
145
157
  logger.error(f"Error importing module {relative_module_path}: {e}")
@@ -158,7 +170,9 @@ class Import(Expression):
158
170
  raise Exception(msg)
159
171
 
160
172
  @staticmethod
161
- def load_expression(module, expressions: list[str] | tuple[str] | str) -> list[Expression] | Expression:
173
+ def load_expression(
174
+ module, expressions: list[str] | tuple[str] | str
175
+ ) -> list[Expression] | Expression:
162
176
  expression_list, return_single = Import._normalize_expressions(expressions)
163
177
  expected_count = len(expression_list)
164
178
  expression_targets = set(expression_list)
@@ -175,23 +189,23 @@ class Import(Expression):
175
189
  sys.path.append(str(parent_dir))
176
190
  module_name = package_path.name
177
191
  else:
178
- module_parts = module.split('/')
192
+ module_parts = module.split("/")
179
193
 
180
- with (package_path / 'package.json').open() as f:
194
+ with (package_path / "package.json").open() as f:
181
195
  pkg = json.load(f)
182
- for expr in pkg['expressions']:
196
+ for expr in pkg["expressions"]:
183
197
  relative_module_path = (
184
198
  f"{module_name}.{expr['module'].replace('/', '.')}"
185
199
  if is_local_path
186
- else '.'.join([*module_parts, expr['module'].replace('/', '.')])
200
+ else ".".join([*module_parts, expr["module"].replace("/", ".")])
187
201
  )
188
202
 
189
- if expr['type'] not in expression_targets:
203
+ if expr["type"] not in expression_targets:
190
204
  continue
191
205
 
192
206
  try:
193
207
  module_obj = importlib.import_module(relative_module_path)
194
- module_class = getattr(module_obj, expr['type'])
208
+ module_class = getattr(module_obj, expr["type"])
195
209
  except (ImportError, ModuleNotFoundError) as e:
196
210
  logger.error(f"Error importing module {relative_module_path}: {e}")
197
211
  raise
@@ -203,11 +217,21 @@ class Import(Expression):
203
217
  assert len(module_classes) > 0, f"Expression '{expressions}' not found in module '{module}'"
204
218
  module_classes_names = [str(class_.__name__) for class_ in module_classes]
205
219
  missing_expressions = [expr for expr in expression_list if expr not in module_classes_names]
206
- assert len(module_classes) == expected_count, f"Not all expressions found in module '{module}'. Could not load {missing_expressions}"
220
+ assert len(module_classes) == expected_count, (
221
+ f"Not all expressions found in module '{module}'. Could not load {missing_expressions}"
222
+ )
207
223
  return module_classes
208
224
 
209
- def __new__(cls, module, auto_clone: bool = True, verbose: bool = False, local_path: str | None = None,
210
- submodules: bool = False, *args, **kwargs):
225
+ def __new__(
226
+ cls,
227
+ module,
228
+ auto_clone: bool = True,
229
+ verbose: bool = False,
230
+ local_path: str | None = None,
231
+ submodules: bool = False,
232
+ *args,
233
+ **kwargs,
234
+ ):
211
235
  """
212
236
  Import a module from GitHub or local path.
213
237
 
@@ -226,12 +250,12 @@ class Import(Expression):
226
250
  if is_local_path:
227
251
  # If module is a local path
228
252
  package_path = module_path_obj
229
- if not (package_path / 'package.json').exists():
253
+ if not (package_path / "package.json").exists():
230
254
  msg = f"No package.json found in {module}"
231
255
  UserMessage(msg)
232
256
  raise ValueError(msg)
233
257
 
234
- with (package_path / 'package.json').open() as f:
258
+ with (package_path / "package.json").open() as f:
235
259
  pkg = json.load(f)
236
260
  else:
237
261
  # Module is a GitHub reference
@@ -241,17 +265,17 @@ class Import(Expression):
241
265
  else:
242
266
  Import.get_from_github(module, submodules)
243
267
 
244
- with (BASE_PACKAGE_PATH / module / 'package.json').open() as f:
268
+ with (BASE_PACKAGE_PATH / module / "package.json").open() as f:
245
269
  pkg = json.load(f)
246
- if 'run' not in pkg:
270
+ if "run" not in pkg:
247
271
  msg = f"Module '{module}' has no 'run' expression defined."
248
272
  UserMessage(msg)
249
273
  raise Exception(msg)
250
- expr = pkg['run']
251
- module_rel = expr['module'].replace('/', '.')
252
- module_parts = module.split('/')
253
- relative_module_path = '.'.join([*module_parts, module_rel])
254
- class_ = expr['type']
274
+ expr = pkg["run"]
275
+ module_rel = expr["module"].replace("/", ".")
276
+ module_parts = module.split("/")
277
+ relative_module_path = ".".join([*module_parts, module_rel])
278
+ class_ = expr["type"]
255
279
  if verbose:
256
280
  logger.info(f"Loading module '{relative_module_path}.{expr['type']}'")
257
281
  module_class = getattr(importlib.import_module(relative_module_path), class_)
@@ -273,7 +297,9 @@ class Import(Expression):
273
297
  """
274
298
  # Determine if module is a local path
275
299
  local_path_obj = Path(local_path) if local_path is not None else None
276
- is_local_path = local_path_obj is not None and local_path_obj.exists() and local_path_obj.is_dir()
300
+ is_local_path = (
301
+ local_path_obj is not None and local_path_obj.exists() and local_path_obj.is_dir()
302
+ )
277
303
 
278
304
  if not Import.exists(module):
279
305
  if is_local_path:
@@ -294,10 +320,12 @@ class Import(Expression):
294
320
  if is_local_path:
295
321
  # For local path, remove directly
296
322
  if module_path_obj.exists():
323
+
297
324
  def del_rw(_action, name, _exc):
298
325
  path_obj = Path(name)
299
326
  path_obj.chmod(stat.S_IWRITE)
300
327
  path_obj.unlink()
328
+
301
329
  shutil.rmtree(module_path_obj, onerror=del_rw)
302
330
  logger.success(f"Removed local module at '{module}'")
303
331
  else:
@@ -306,15 +334,17 @@ class Import(Expression):
306
334
  # For GitHub modules, remove from packages directory
307
335
  module_path = BASE_PACKAGE_PATH / module
308
336
  if module_path.exists():
337
+
309
338
  def del_rw(_action, name, _exc):
310
339
  path_obj = Path(name)
311
340
  path_obj.chmod(stat.S_IWRITE)
312
341
  path_obj.unlink()
342
+
313
343
  shutil.rmtree(module_path, onerror=del_rw)
314
344
  logger.success(f"Removed module '{module}'")
315
345
 
316
346
  # Check if folder is empty and remove it
317
- parent_path = BASE_PACKAGE_PATH / module.split('/')[0]
347
+ parent_path = BASE_PACKAGE_PATH / module.split("/")[0]
318
348
  if parent_path.exists() and not any(parent_path.iterdir()):
319
349
  parent_path.rmdir()
320
350
  logger.info(f"Removed empty parent folder '{parent_path}'")
@@ -329,7 +359,9 @@ class Import(Expression):
329
359
 
330
360
  sub_dirs = []
331
361
  for base_dir in base_dirs:
332
- sub_dirs.extend([f'{base_dir.name}/{entry.name}' for entry in base_dir.iterdir() if entry.is_dir()])
362
+ sub_dirs.extend(
363
+ [f"{base_dir.name}/{entry.name}" for entry in base_dir.iterdir() if entry.is_dir()]
364
+ )
333
365
 
334
366
  return sub_dirs
335
367
 
@@ -347,16 +379,18 @@ class Import(Expression):
347
379
  is_local_path = module_path_obj.exists() and module_path_obj.is_dir()
348
380
 
349
381
  # Use the appropriate path based on whether it's local or not
350
- module_path = module_path_obj if is_local_path else BASE_PACKAGE_PATH / module.replace(".", "/")
382
+ module_path = (
383
+ module_path_obj if is_local_path else BASE_PACKAGE_PATH / module.replace(".", "/")
384
+ )
351
385
 
352
386
  # Construct the git pull command based on whether submodules should be included
353
- pull_cmd = ['git', '-C', str(module_path)]
387
+ pull_cmd = ["git", "-C", str(module_path)]
354
388
  if submodules:
355
- pull_cmd.extend(['pull', '--recurse-submodules'])
389
+ pull_cmd.extend(["pull", "--recurse-submodules"])
356
390
  subprocess.check_call(pull_cmd)
357
391
  logger.success(f"Module '{module}' and its submodules updated.")
358
392
  else:
359
- pull_cmd.extend(['pull'])
393
+ pull_cmd.extend(["pull"])
360
394
  subprocess.check_call(pull_cmd)
361
395
  logger.success(f"Module '{module}' updated.")
362
396
  else:
symai/interfaces.py CHANGED
@@ -94,7 +94,7 @@ def cfg_to_interface():
94
94
  _add_tts_interface(mapping)
95
95
 
96
96
  mapping["indexing"] = Interface("naive_vectordb")
97
- mapping["scraper"] = Interface("naive_webscraping")
97
+ mapping["scraper"] = Interface("naive_scrape")
98
98
  mapping["stt"] = Interface("whisper")
99
99
  mapping["file"] = Interface("file")
100
100
 
symai/memory.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  from . import core_ext
3
2
  from .components import Function
4
3
  from .symbol import Expression, Symbol
@@ -25,52 +24,56 @@ class SlidingWindowListMemory(Memory):
25
24
  def __init__(self, window_size: int = 10, max_size: int = 1000, **kwargs):
26
25
  super().__init__(**kwargs)
27
26
  self._memory: list[str] = []
28
- self._window_size: int = window_size
29
- self._max_size: int = max_size
27
+ self._window_size: int = window_size
28
+ self._max_size: int = max_size
30
29
 
31
30
  def store(self, query: str, *_args, **_kwargs):
32
31
  self._memory.append(query)
33
32
  if len(self._memory) > self._max_size:
34
- self._memory = self._memory[-self._max_size:]
33
+ self._memory = self._memory[-self._max_size :]
35
34
 
36
35
  def forget(self, query: Symbol, *_args, **_kwargs):
37
36
  self._memory.remove(query)
38
37
 
39
38
  def recall(self, *_args, **_kwargs):
40
- return self._memory[-self._window_size:]
39
+ return self._memory[-self._window_size :]
41
40
 
42
41
 
43
42
  class SlidingWindowStringConcatMemory(Memory):
44
43
  def __init__(self, *_args, **kwargs):
45
44
  super().__init__(**kwargs)
46
- self._memory: str = ''
47
- self.marker: str = '[--++=|=++--]'
45
+ self._memory: str = ""
46
+ self.marker: str = "[--++=|=++--]"
48
47
 
49
- @core_ext.bind(engine='neurosymbolic', property='max_context_tokens')
50
- def max_tokens(self): pass
48
+ @core_ext.bind(engine="neurosymbolic", property="max_context_tokens")
49
+ def max_tokens(self):
50
+ pass
51
51
 
52
52
  def __getstate__(self):
53
53
  state = super().__getstate__().copy()
54
54
  # Exclude the max_tokens property from being serialized
55
- state.pop('_max_tokens', None)
55
+ state.pop("_max_tokens", None)
56
56
  return state
57
57
 
58
58
  def __setstate__(self, state):
59
59
  self.__dict__.update(state)
60
+
60
61
  # Initialize _max_tokens as None, it should be set again after deserialization
61
- @core_ext.bind(engine='neurosymbolic', property='max_context_tokens')
62
- def _max_tokens(self): pass
62
+ @core_ext.bind(engine="neurosymbolic", property="max_context_tokens")
63
+ def _max_tokens(self):
64
+ pass
65
+
63
66
  self.max_tokens = _max_tokens
64
67
 
65
68
  def history(self):
66
69
  return [hist for hist in self._memory.split(self.marker) if hist]
67
70
 
68
71
  def drop(self):
69
- self._memory = ''
72
+ self._memory = ""
70
73
 
71
74
  def store(self, query: str):
72
75
  # append to string to memory
73
- self._memory += f'{query!s}{self.marker}'
76
+ self._memory += f"{query!s}{self.marker}"
74
77
 
75
78
  def forget(self, query: Symbol, *_args, **_kwargs):
76
79
  # remove substring from memory
@@ -78,29 +81,33 @@ class SlidingWindowStringConcatMemory(Memory):
78
81
  self._memory = str(sym - query)
79
82
 
80
83
  def recall(self, query: str, *args, **kwargs) -> Symbol:
81
- hist = self.history()
82
- memory = ''
84
+ hist = self.history()
85
+ memory = ""
83
86
  if len(hist) > 0:
84
- memory = '[MEMORY]\n'
85
- val = '\n'.join(hist)
87
+ memory = "[MEMORY]\n"
88
+ val = "\n".join(hist)
86
89
  memory += val
87
90
  that = self
91
+
88
92
  class Recall(Function):
89
93
  @property
90
94
  def static_context(self):
91
95
  return that.static_context
96
+
92
97
  func = Recall(memory)
93
98
  return func(query, *args, **kwargs)
94
99
 
95
100
 
96
101
  class VectorDatabaseMemory(Memory):
97
- def __init__(self, enabled: bool = True, top_k: int = 3, index_name: str = 'defaultindex', **kwargs):
102
+ def __init__(
103
+ self, enabled: bool = True, top_k: int = 3, index_name: str = "defaultindex", **kwargs
104
+ ):
98
105
  super().__init__(**kwargs)
99
106
  self.enabled: bool = enabled
100
- self.top_k: int = top_k
101
- self.index_name = index_name
107
+ self.top_k: int = top_k
108
+ self.index_name = index_name
102
109
 
103
- def store(self, query: str , *_args, **_kwargs):
110
+ def store(self, query: str, *_args, **_kwargs):
104
111
  if not self.enabled:
105
112
  return
106
113
 
@@ -110,6 +117,8 @@ class VectorDatabaseMemory(Memory):
110
117
  if not self.enabled:
111
118
  return None
112
119
 
113
- res = self.get(Symbol(query).embed().value, index_top_k=self.top_k, index_name=self.index_name).ast()
120
+ res = self.get(
121
+ Symbol(query).embed().value, index_top_k=self.top_k, index_name=self.index_name
122
+ ).ast()
114
123
 
115
- return [v['metadata']['text'] for v in res['matches']]
124
+ return [v["metadata"]["text"] for v in res["matches"]]
symai/menu/screen.py CHANGED
@@ -6,42 +6,51 @@ from ..misc.console import ConsoleStyle
6
6
 
7
7
 
8
8
  def show_splash_screen(print: callable = print_formatted_text):
9
- print('\n\n')
10
- print('- '*42)
11
- print('=='*41 + '=')
12
- print(r'''
9
+ print("\n\n")
10
+ print("- " * 42)
11
+ print("==" * 41 + "=")
12
+ print(
13
+ r"""
13
14
  ____| | _) | \ _ _|
14
15
  __| \ \ / __| _ \ __ \ __| | __| | | _ \ |
15
16
  | ` < | __/ | | \__ \ | | | | ___ \ |
16
17
  _____| _/\_\ \__| \___| _| _| ____/ _| \__| \__, | _/ _\ ___|
17
18
  ____/
18
- ''', escape=True)
19
- print('- '*42)
19
+ """,
20
+ escape=True,
21
+ )
22
+ print("- " * 42)
20
23
 
21
24
 
22
25
  def show_info_message(print: callable = print_formatted_text):
23
- print('Welcome to SymbolicAI!' + '\n')
24
- print('SymbolicAI is an open-source Python project for building AI-powered applications\nand assistants.')
25
- print('We utilize the power of large language models and the latest research in AI.' + '\n')
26
- print('SymbolicAI is backed by ExtensityAI. We are committed to open research,\nthe democratization of AI tools and much more ...' + '\n')
26
+ print("Welcome to SymbolicAI!" + "\n")
27
+ print(
28
+ "SymbolicAI is an open-source Python project for building AI-powered applications\nand assistants."
29
+ )
30
+ print("We utilize the power of large language models and the latest research in AI." + "\n")
31
+ print(
32
+ "SymbolicAI is backed by ExtensityAI. We are committed to open research,\nthe democratization of AI tools and much more ..."
33
+ "\n"
34
+ )
27
35
 
28
- print('... and we also like peanut butter and jelly sandwiches, and cookies.' + '\n\n')
29
- print('If you like what we are doing please help us achieve our mission!')
30
- print('More information is available at https://www.extensity.ai' + '\n')
36
+ print("... and we also like peanut butter and jelly sandwiches, and cookies." + "\n\n")
37
+ print("If you like what we are doing please help us achieve our mission!")
38
+ print("More information is available at https://www.extensity.ai" + "\n")
31
39
 
32
40
 
33
41
  def show_separator(print: callable = print_formatted_text):
34
- print('- '*42 + '\n')
42
+ print("- " * 42 + "\n")
35
43
 
36
44
 
37
45
  def show_intro_menu():
38
- if os.environ.get('SYMAI_WARNINGS', '1') == '1':
39
- with ConsoleStyle('extensity') as console:
46
+ if os.environ.get("SYMAI_WARNINGS", "1") == "1":
47
+ with ConsoleStyle("extensity") as console:
40
48
  show_splash_screen(print=console.print)
41
- with ConsoleStyle('text') as console:
49
+ with ConsoleStyle("text") as console:
42
50
  show_info_message(print=console.print)
43
- with ConsoleStyle('extensity') as console:
51
+ with ConsoleStyle("extensity") as console:
44
52
  show_separator(print=console.print)
45
53
 
46
- if __name__ == '__main__':
54
+
55
+ if __name__ == "__main__":
47
56
  show_intro_menu()
symai/misc/console.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import re
3
3
 
4
- #@TODO: refactor to use rich instead of prompt_toolkit
4
+ # @TODO: refactor to use rich instead of prompt_toolkit
5
5
  from html import escape as escape_html
6
6
  from typing import ClassVar
7
7
 
@@ -14,28 +14,28 @@ from pygments.lexers.python import PythonLexer
14
14
  from pygments.lexers.shell import BashLexer
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
- print = print_formatted_text # noqa
17
+ print = print_formatted_text # noqa
18
18
 
19
19
 
20
20
  class ConsoleStyle:
21
21
  style_types: ClassVar[dict[str, str]] = {
22
- 'alert': 'orange',
23
- 'error': 'ansired',
24
- 'warn': 'ansiyellow',
25
- 'info': 'ansiblue',
26
- 'success': 'ansigreen',
27
- 'extensity': '#009499',
28
- 'text': 'ansigray',
29
- 'debug': 'gray',
30
- 'custom': 'custom',
31
- 'code': 'code',
32
- 'default': '',
22
+ "alert": "orange",
23
+ "error": "ansired",
24
+ "warn": "ansiyellow",
25
+ "info": "ansiblue",
26
+ "success": "ansigreen",
27
+ "extensity": "#009499",
28
+ "text": "ansigray",
29
+ "debug": "gray",
30
+ "custom": "custom",
31
+ "code": "code",
32
+ "default": "",
33
33
  }
34
34
 
35
- def __init__(self, style_type = '', color = '', logging: bool = False):
35
+ def __init__(self, style_type="", color="", logging: bool = False):
36
36
  self.style_type = style_type
37
- self.color = color
38
- self.logging = logging
37
+ self.color = color
38
+ self.logging = logging
39
39
 
40
40
  def __call__(self, message):
41
41
  self.print(message)
@@ -52,43 +52,43 @@ class ConsoleStyle:
52
52
  logger.debug(message)
53
53
  # Prepare safe content for HTML printing without mutating the original
54
54
  content_for_html = escape_html(message) if escape else message
55
- style = self.style_types.get(self.style_type, self.style_types['default'])
55
+ style = self.style_types.get(self.style_type, self.style_types["default"])
56
56
 
57
- if style == self.style_types['code']:
57
+ if style == self.style_types["code"]:
58
58
  self._print_code_message(message)
59
59
  return
60
- if style == self.style_types['default']:
60
+ if style == self.style_types["default"]:
61
61
  print(message)
62
62
  return
63
- if style == self.style_types['custom']:
63
+ if style == self.style_types["custom"]:
64
64
  self._print_html(self.color, content_for_html)
65
65
  return
66
66
  self._print_html(style, content_for_html)
67
67
 
68
68
  def _print_code_message(self, message: str) -> None:
69
- segments = re.split(r'(```)', message)
69
+ segments = re.split(r"(```)", message)
70
70
  is_code_segment = False
71
71
  for segment in segments:
72
- if segment == '```':
72
+ if segment == "```":
73
73
  is_code_segment = not is_code_segment
74
74
  continue
75
75
  if is_code_segment:
76
76
  self._print_code_segment(segment)
77
77
  continue
78
- print(segment, end='\n')
78
+ print(segment, end="\n")
79
79
 
80
80
  def _print_code_segment(self, segment: str) -> None:
81
81
  lexer = self._select_lexer(segment)
82
82
  tokens = list(pygments.lex("```" + segment + "```", lexer))
83
- print(PygmentsTokens(tokens), end='')
83
+ print(PygmentsTokens(tokens), end="")
84
84
 
85
85
  def _select_lexer(self, segment: str):
86
86
  lowered_segment = segment.lower()
87
- if 'python' in lowered_segment:
87
+ if "python" in lowered_segment:
88
88
  return PythonLexer()
89
- if 'javascript' in lowered_segment or 'typescript' in lowered_segment:
89
+ if "javascript" in lowered_segment or "typescript" in lowered_segment:
90
90
  return JavascriptLexer()
91
- if 'c++' in lowered_segment:
91
+ if "c++" in lowered_segment:
92
92
  return CppLexer()
93
93
  return BashLexer()
94
94