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.
- symai/__init__.py +96 -64
- symai/backend/base.py +93 -80
- symai/backend/engines/drawing/engine_bfl.py +12 -11
- symai/backend/engines/drawing/engine_gpt_image.py +108 -87
- symai/backend/engines/embedding/engine_llama_cpp.py +25 -28
- symai/backend/engines/embedding/engine_openai.py +3 -5
- symai/backend/engines/execute/engine_python.py +6 -5
- symai/backend/engines/files/engine_io.py +74 -67
- symai/backend/engines/imagecaptioning/engine_blip2.py +3 -3
- symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +54 -38
- symai/backend/engines/index/engine_pinecone.py +23 -24
- symai/backend/engines/index/engine_vectordb.py +16 -14
- symai/backend/engines/lean/engine_lean4.py +38 -34
- symai/backend/engines/neurosymbolic/__init__.py +41 -13
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +262 -182
- symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +263 -191
- symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +53 -49
- symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +212 -211
- symai/backend/engines/neurosymbolic/engine_groq.py +87 -63
- symai/backend/engines/neurosymbolic/engine_huggingface.py +21 -24
- symai/backend/engines/neurosymbolic/engine_llama_cpp.py +117 -48
- symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +256 -229
- symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +270 -150
- symai/backend/engines/ocr/engine_apilayer.py +6 -8
- symai/backend/engines/output/engine_stdout.py +1 -4
- symai/backend/engines/search/engine_openai.py +7 -7
- symai/backend/engines/search/engine_perplexity.py +5 -5
- symai/backend/engines/search/engine_serpapi.py +12 -14
- symai/backend/engines/speech_to_text/engine_local_whisper.py +20 -27
- symai/backend/engines/symbolic/engine_wolframalpha.py +3 -3
- symai/backend/engines/text_to_speech/engine_openai.py +5 -7
- symai/backend/engines/text_vision/engine_clip.py +7 -11
- symai/backend/engines/userinput/engine_console.py +3 -3
- symai/backend/engines/webscraping/engine_requests.py +81 -48
- symai/backend/mixin/__init__.py +13 -0
- symai/backend/mixin/anthropic.py +4 -2
- symai/backend/mixin/deepseek.py +2 -0
- symai/backend/mixin/google.py +2 -0
- symai/backend/mixin/openai.py +11 -3
- symai/backend/settings.py +83 -16
- symai/chat.py +101 -78
- symai/collect/__init__.py +7 -1
- symai/collect/dynamic.py +77 -69
- symai/collect/pipeline.py +35 -27
- symai/collect/stats.py +75 -63
- symai/components.py +198 -169
- symai/constraints.py +15 -12
- symai/core.py +698 -359
- symai/core_ext.py +32 -34
- symai/endpoints/api.py +80 -73
- symai/extended/.DS_Store +0 -0
- symai/extended/__init__.py +46 -12
- symai/extended/api_builder.py +11 -8
- symai/extended/arxiv_pdf_parser.py +13 -12
- symai/extended/bibtex_parser.py +2 -3
- symai/extended/conversation.py +101 -90
- symai/extended/document.py +17 -10
- symai/extended/file_merger.py +18 -13
- symai/extended/graph.py +18 -13
- symai/extended/html_style_template.py +2 -4
- symai/extended/interfaces/blip_2.py +1 -2
- symai/extended/interfaces/clip.py +1 -2
- symai/extended/interfaces/console.py +7 -1
- symai/extended/interfaces/dall_e.py +1 -1
- symai/extended/interfaces/flux.py +1 -1
- symai/extended/interfaces/gpt_image.py +1 -1
- symai/extended/interfaces/input.py +1 -1
- symai/extended/interfaces/llava.py +0 -1
- symai/extended/interfaces/naive_vectordb.py +7 -8
- symai/extended/interfaces/naive_webscraping.py +1 -1
- symai/extended/interfaces/ocr.py +1 -1
- symai/extended/interfaces/pinecone.py +6 -5
- symai/extended/interfaces/serpapi.py +1 -1
- symai/extended/interfaces/terminal.py +2 -3
- symai/extended/interfaces/tts.py +1 -1
- symai/extended/interfaces/whisper.py +1 -1
- symai/extended/interfaces/wolframalpha.py +1 -1
- symai/extended/metrics/__init__.py +11 -1
- symai/extended/metrics/similarity.py +11 -13
- symai/extended/os_command.py +17 -16
- symai/extended/packages/__init__.py +29 -3
- symai/extended/packages/symdev.py +19 -16
- symai/extended/packages/sympkg.py +12 -9
- symai/extended/packages/symrun.py +21 -19
- symai/extended/repo_cloner.py +11 -10
- symai/extended/seo_query_optimizer.py +1 -2
- symai/extended/solver.py +20 -23
- symai/extended/summarizer.py +4 -3
- symai/extended/taypan_interpreter.py +10 -12
- symai/extended/vectordb.py +99 -82
- symai/formatter/__init__.py +9 -1
- symai/formatter/formatter.py +12 -16
- symai/formatter/regex.py +62 -63
- symai/functional.py +176 -122
- symai/imports.py +136 -127
- symai/interfaces.py +56 -27
- symai/memory.py +14 -13
- symai/misc/console.py +49 -39
- symai/misc/loader.py +5 -3
- symai/models/__init__.py +17 -1
- symai/models/base.py +269 -181
- symai/models/errors.py +0 -1
- symai/ops/__init__.py +32 -22
- symai/ops/measures.py +11 -15
- symai/ops/primitives.py +348 -228
- symai/post_processors.py +32 -28
- symai/pre_processors.py +39 -41
- symai/processor.py +6 -4
- symai/prompts.py +59 -45
- symai/server/huggingface_server.py +23 -20
- symai/server/llama_cpp_server.py +7 -5
- symai/shell.py +3 -4
- symai/shellsv.py +499 -375
- symai/strategy.py +517 -287
- symai/symbol.py +111 -116
- symai/utils.py +42 -36
- {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/METADATA +4 -2
- symbolicai-1.0.0.dist-info/RECORD +163 -0
- symbolicai-0.20.2.dist-info/RECORD +0 -162
- {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/WHEEL +0 -0
- {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/entry_points.txt +0 -0
- {symbolicai-0.20.2.dist-info → symbolicai-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {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:
|
|
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:
|
|
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
|
-
|
|
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(*
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
from fastapi import
|
|
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
|
|
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
|
|
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
|
-
|
|
30
|
+
UserMessage(f"Redis server is running at {host}:{port}")
|
|
31
31
|
return True
|
|
32
|
-
except
|
|
33
|
-
|
|
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
|
-
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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[
|
|
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:
|
|
129
|
-
static_context:
|
|
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:
|
|
139
|
-
kwargs:
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
282
|
-
init_kwargs:
|
|
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:
|
|
289
|
-
init_kwargs:
|
|
290
|
-
forward_args:
|
|
291
|
-
forward_kwargs:
|
|
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:
|
|
305
|
+
update_kwargs: dict[str, Any] = {}
|
|
296
306
|
|
|
297
307
|
|
|
298
308
|
@app.post("/components/")
|
|
299
|
-
def create_component(request: CreateComponentGenericRequest,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
363
|
-
|
|
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:
|
|
379
|
-
init_kwargs:
|
|
384
|
+
init_args: list[Any] = []
|
|
385
|
+
init_kwargs: dict[str, Any] = {}
|
|
380
386
|
|
|
381
387
|
|
|
382
388
|
class UpdateExtendedRequest(BaseModel):
|
|
383
|
-
update_kwargs:
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
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: {
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
symai/extended/.DS_Store
ADDED
|
Binary file
|
symai/extended/__init__.py
CHANGED
|
@@ -1,16 +1,50 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
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
|
symai/extended/api_builder.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from .. import core
|
|
2
|
-
from ..
|
|
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 ..
|
|
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 '$> {
|
|
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, **
|
|
129
|
+
def forward(self, request: Symbol, **_kwargs) -> Symbol:
|
|
130
130
|
self._request = self._to_symbol(request)
|
|
131
|
-
if self._verbose:
|
|
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:
|
|
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:
|
|
139
|
+
if self._verbose:
|
|
140
|
+
UserMessage(f'[RESULT]: {self._result}')
|
|
138
141
|
self._value = self._result
|
|
139
142
|
return self
|