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
@@ -0,0 +1,328 @@
1
+ import json
2
+ import logging
3
+ import re
4
+ from copy import deepcopy
5
+
6
+ from cerebras.cloud.sdk import Cerebras
7
+
8
+ from ....components import SelfPrompt
9
+ from ....core_ext import retry
10
+ from ....utils import UserMessage
11
+ from ...base import Engine
12
+ from ...settings import SYMAI_CONFIG
13
+
14
+ logging.getLogger("cerebras").setLevel(logging.ERROR)
15
+ logging.getLogger("requests").setLevel(logging.ERROR)
16
+ logging.getLogger("urllib").setLevel(logging.ERROR)
17
+ logging.getLogger("httpx").setLevel(logging.ERROR)
18
+ logging.getLogger("httpcore").setLevel(logging.ERROR)
19
+
20
+
21
+ _NON_VERBOSE_OUTPUT = (
22
+ "<META_INSTRUCTION/>\n"
23
+ "You do not output anything else, like verbose preambles or post explanation, such as "
24
+ '"Sure, let me...", "Hope that was helpful...", "Yes, I can help you with that...", etc. '
25
+ "Consider well formatted output, e.g. for sentences use punctuation, spaces etc. or for code use "
26
+ "indentation, etc. Never add meta instructions information to your output!\n\n"
27
+ )
28
+
29
+
30
+ class CerebrasEngine(Engine):
31
+ def __init__(self, api_key: str | None = None, model: str | None = None):
32
+ super().__init__()
33
+ self.config = deepcopy(SYMAI_CONFIG)
34
+ # In case we use EngineRepository.register to inject the api_key and model => dynamically change the engine at runtime
35
+ if api_key is not None and model is not None:
36
+ self.config["NEUROSYMBOLIC_ENGINE_API_KEY"] = api_key
37
+ self.config["NEUROSYMBOLIC_ENGINE_MODEL"] = model
38
+ if self.id() != "neurosymbolic":
39
+ # Do not initialize if not neurosymbolic; avoids conflict with llama.cpp check in
40
+ # EngineRepository.register_from_package.
41
+ return
42
+
43
+ self.api_key = self.config["NEUROSYMBOLIC_ENGINE_API_KEY"]
44
+ self.model = self.config["NEUROSYMBOLIC_ENGINE_MODEL"]
45
+ self.seed = None
46
+ self.name = self.__class__.__name__
47
+
48
+ try:
49
+ self.client = Cerebras(api_key=self.api_key)
50
+ except Exception as exc:
51
+ UserMessage(
52
+ f"Failed to initialize Cerebras client. Please check your Cerebras SDK installation. Caused by: {exc}",
53
+ raise_with=ValueError,
54
+ )
55
+
56
+ def id(self) -> str:
57
+ model_name = self.config.get("NEUROSYMBOLIC_ENGINE_MODEL")
58
+ if model_name and model_name.startswith("cerebras"):
59
+ return "neurosymbolic"
60
+ return super().id()
61
+
62
+ def command(self, *args, **kwargs):
63
+ super().command(*args, **kwargs)
64
+ if "NEUROSYMBOLIC_ENGINE_API_KEY" in kwargs:
65
+ self.api_key = kwargs["NEUROSYMBOLIC_ENGINE_API_KEY"]
66
+ try:
67
+ self.client = Cerebras(api_key=self.api_key)
68
+ except Exception as exc:
69
+ UserMessage(
70
+ f"Failed to reinitialize Cerebras client. Caused by: {exc}",
71
+ raise_with=ValueError,
72
+ )
73
+ if "NEUROSYMBOLIC_ENGINE_MODEL" in kwargs:
74
+ self.model = kwargs["NEUROSYMBOLIC_ENGINE_MODEL"]
75
+ if "seed" in kwargs:
76
+ self.seed = kwargs["seed"]
77
+
78
+ def compute_required_tokens(self, _messages):
79
+ UserMessage(
80
+ "Token counting not implemented for this engine.", raise_with=NotImplementedError
81
+ )
82
+
83
+ def compute_remaining_tokens(self, _prompts: list) -> int:
84
+ UserMessage(
85
+ "Token counting not implemented for this engine.", raise_with=NotImplementedError
86
+ )
87
+
88
+ def _handle_prefix(self, model_name: str) -> str:
89
+ """Handle prefix for model name."""
90
+ return model_name.replace("cerebras:", "")
91
+
92
+ def _extract_thinking_content(self, outputs: list[str]) -> tuple[str | None, list[str]]:
93
+ """Extract thinking content from textual output using <think>...</think> tags if present."""
94
+ if not outputs:
95
+ return None, outputs
96
+
97
+ content = outputs[0]
98
+ if not content:
99
+ return None, outputs
100
+
101
+ # This regular expression matches a <think>...</think> block and captures any content between the tags,
102
+ # including newlines, so that we can separate internal reasoning text from the user-facing answer.
103
+ think_pattern = r"<think>(.*?)</think>"
104
+ match = re.search(think_pattern, content, re.DOTALL)
105
+
106
+ thinking_content = None
107
+ if match:
108
+ thinking_content = match.group(1).strip() or None
109
+
110
+ cleaned_content = re.sub(think_pattern, "", content, flags=re.DOTALL).strip()
111
+ cleaned_outputs = [cleaned_content, *outputs[1:]]
112
+
113
+ return thinking_content, cleaned_outputs
114
+
115
+ # cumulative wait time is < 30s
116
+ @retry(tries=8, delay=0.5, backoff=1.5, max_delay=5, jitter=(0, 0.5))
117
+ def forward(self, argument):
118
+ kwargs = argument.kwargs
119
+ messages = argument.prop.prepared_input
120
+ payload = self._prepare_request_payload(messages, argument)
121
+ except_remedy = kwargs.get("except_remedy")
122
+
123
+ try:
124
+ res = self.client.chat.completions.create(**payload)
125
+ except Exception as exc: # pragma: no cover - defensive path
126
+ res = self._handle_forward_exception(exc, argument, kwargs, except_remedy)
127
+
128
+ return self._build_outputs_and_metadata(res, payload)
129
+
130
+ def _handle_forward_exception(self, exc, argument, kwargs, except_remedy):
131
+ if self.api_key is None or self.api_key == "":
132
+ msg = (
133
+ "Cerebras API key is not set. Please set it in the config file or "
134
+ "pass it as an argument to the command method."
135
+ )
136
+ UserMessage(msg)
137
+ config_key = self.config.get("NEUROSYMBOLIC_ENGINE_API_KEY")
138
+ if config_key is None or config_key == "":
139
+ UserMessage(msg, raise_with=ValueError)
140
+ self.api_key = config_key
141
+ try:
142
+ self.client = Cerebras(api_key=self.api_key)
143
+ except Exception as inner_exc:
144
+ UserMessage(
145
+ f"Failed to initialize Cerebras client after missing API key. Caused by: {inner_exc}",
146
+ raise_with=ValueError,
147
+ )
148
+
149
+ callback = self.client.chat.completions.create
150
+ kwargs["model"] = (
151
+ self._handle_prefix(kwargs["model"])
152
+ if "model" in kwargs
153
+ else self._handle_prefix(self.model)
154
+ )
155
+
156
+ if except_remedy is not None:
157
+ return except_remedy(self, exc, callback, argument)
158
+
159
+ UserMessage(f"Error during generation. Caused by: {exc}", raise_with=ValueError)
160
+ return None
161
+
162
+ def _build_outputs_and_metadata(self, res, payload):
163
+ metadata: dict = {"raw_output": res}
164
+ if payload.get("tools"):
165
+ metadata = self._process_function_calls(res, metadata)
166
+
167
+ outputs: list[str] = []
168
+ thinking_content: str | None = None
169
+
170
+ for choice in res.choices:
171
+ message = choice.message
172
+ outputs.append(getattr(message, "content", "") or "")
173
+ if thinking_content is None:
174
+ reasoning = getattr(message, "reasoning", None)
175
+ if reasoning:
176
+ thinking_content = reasoning
177
+
178
+ if thinking_content is None:
179
+ thinking_content, outputs = self._extract_thinking_content(outputs)
180
+ else:
181
+ _, outputs = self._extract_thinking_content(outputs)
182
+
183
+ if thinking_content:
184
+ metadata["thinking"] = thinking_content
185
+
186
+ return outputs, metadata
187
+
188
+ def _prepare_raw_input(self, argument):
189
+ if not argument.prop.processed_input:
190
+ UserMessage(
191
+ "Need to provide a prompt instruction to the engine if raw_input is enabled.",
192
+ raise_with=ValueError,
193
+ )
194
+ value = argument.prop.processed_input
195
+ if not isinstance(value, list):
196
+ if not isinstance(value, dict):
197
+ value = {"role": "user", "content": str(value)}
198
+ value = [value]
199
+ return value
200
+
201
+ def prepare(self, argument):
202
+ if argument.prop.raw_input:
203
+ argument.prop.prepared_input = self._prepare_raw_input(argument)
204
+ return
205
+ self._validate_response_format(argument)
206
+
207
+ system_message = self._build_system_message(argument)
208
+ user_content = self._build_user_content(argument)
209
+ user_prompt = {"role": "user", "content": user_content}
210
+ system_message, user_prompt = self._apply_self_prompt_if_needed(
211
+ argument, system_message, user_prompt
212
+ )
213
+
214
+ argument.prop.prepared_input = [
215
+ {"role": "system", "content": system_message},
216
+ user_prompt,
217
+ ]
218
+
219
+ def _validate_response_format(self, argument) -> None:
220
+ if argument.prop.response_format:
221
+ response_format = argument.prop.response_format
222
+ assert response_format.get("type") is not None, (
223
+ 'Expected format `{ "type": "json_object" }` for JSON mode. '
224
+ "See Cerebras structured outputs documentation for details."
225
+ )
226
+
227
+ def _build_system_message(self, argument) -> str:
228
+ system_message: str = ""
229
+ if argument.prop.suppress_verbose_output:
230
+ system_message += _NON_VERBOSE_OUTPUT
231
+ if system_message:
232
+ system_message = f"{system_message}\n"
233
+
234
+ ref = argument.prop.instance
235
+ static_context, dynamic_context = ref.global_context
236
+ if len(static_context) > 0:
237
+ system_message += f"<STATIC CONTEXT/>\n{static_context}\n\n"
238
+
239
+ if len(dynamic_context) > 0:
240
+ system_message += f"<DYNAMIC CONTEXT/>\n{dynamic_context}\n\n"
241
+
242
+ if argument.prop.payload:
243
+ system_message += f"<ADDITIONAL CONTEXT/>\n{argument.prop.payload!s}\n\n"
244
+
245
+ examples = argument.prop.examples
246
+ if examples and len(examples) > 0:
247
+ system_message += f"<EXAMPLES/>\n{examples!s}\n\n"
248
+
249
+ if argument.prop.prompt is not None and len(argument.prop.prompt) > 0:
250
+ prompt_value = str(argument.prop.prompt)
251
+ system_message += f"<INSTRUCTION/>\n{prompt_value}\n\n"
252
+
253
+ if argument.prop.template_suffix:
254
+ system_message += (
255
+ " You will only generate content for the placeholder "
256
+ f"`{argument.prop.template_suffix!s}` following the instructions and the provided context information.\n\n"
257
+ )
258
+
259
+ return system_message
260
+
261
+ def _build_user_content(self, argument) -> str:
262
+ return str(argument.prop.processed_input)
263
+
264
+ def _apply_self_prompt_if_needed(self, argument, system_message, user_prompt):
265
+ if argument.prop.instance._kwargs.get("self_prompt", False) or argument.prop.self_prompt:
266
+ self_prompter = SelfPrompt()
267
+ result = self_prompter({"user": user_prompt["content"], "system": system_message})
268
+ if result is None:
269
+ UserMessage("Self-prompting failed!", raise_with=ValueError)
270
+ return result["system"], {"role": "user", "content": result["user"]}
271
+ return system_message, user_prompt
272
+
273
+ def _process_function_calls(self, res, metadata):
274
+ hit = False
275
+ if (
276
+ hasattr(res, "choices")
277
+ and res.choices
278
+ and hasattr(res.choices[0], "message")
279
+ and res.choices[0].message
280
+ and hasattr(res.choices[0].message, "tool_calls")
281
+ and res.choices[0].message.tool_calls
282
+ ):
283
+ for tool_call in res.choices[0].message.tool_calls:
284
+ if hasattr(tool_call, "function") and tool_call.function:
285
+ if hit:
286
+ UserMessage(
287
+ "Multiple function calls detected in the response but only the first one will be processed."
288
+ )
289
+ break
290
+ try:
291
+ args_dict = json.loads(tool_call.function.arguments)
292
+ except json.JSONDecodeError:
293
+ args_dict = {}
294
+ metadata["function_call"] = {
295
+ "name": tool_call.function.name,
296
+ "arguments": args_dict,
297
+ }
298
+ hit = True
299
+ return metadata
300
+
301
+ def _prepare_request_payload(self, messages, argument):
302
+ """Prepares the request payload from the argument."""
303
+ kwargs = argument.kwargs
304
+
305
+ n = kwargs.get("n", 1)
306
+ if n > 1:
307
+ UserMessage(
308
+ "If N is supplied, it must be equal to 1. We default to 1 to avoid unexpected batch behavior."
309
+ )
310
+ n = 1
311
+
312
+ response_format = kwargs.get("response_format")
313
+
314
+ return {
315
+ "messages": messages,
316
+ "model": self._handle_prefix(kwargs.get("model", self.model)),
317
+ "max_completion_tokens": kwargs.get("max_completion_tokens"),
318
+ "stop": kwargs.get("stop"),
319
+ "temperature": kwargs.get("temperature", 1),
320
+ "top_p": kwargs.get("top_p", 1),
321
+ "n": n,
322
+ "tools": kwargs.get("tools"),
323
+ "parallel_tool_calls": kwargs.get("parallel_tool_calls"),
324
+ "response_format": response_format,
325
+ "reasoning_effort": kwargs.get("reasoning_effort"),
326
+ "disable_reasoning": kwargs.get("disable_reasoning"),
327
+ "stream": kwargs.get("stream", False),
328
+ }
@@ -22,12 +22,12 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
22
22
  self.config = deepcopy(SYMAI_CONFIG)
23
23
  # In case we use EngineRepository.register to inject the api_key and model => dynamically change the engine at runtime
24
24
  if api_key is not None and model is not None:
25
- self.config['NEUROSYMBOLIC_ENGINE_API_KEY'] = api_key
26
- self.config['NEUROSYMBOLIC_ENGINE_MODEL'] = model
27
- if self.id() != 'neurosymbolic':
28
- return # do not initialize if not neurosymbolic; avoids conflict with llama.cpp check in EngineRepository.register_from_package
29
- self.api_key = self.config['NEUROSYMBOLIC_ENGINE_API_KEY']
30
- self.model = self.config['NEUROSYMBOLIC_ENGINE_MODEL']
25
+ self.config["NEUROSYMBOLIC_ENGINE_API_KEY"] = api_key
26
+ self.config["NEUROSYMBOLIC_ENGINE_MODEL"] = model
27
+ if self.id() != "neurosymbolic":
28
+ return # do not initialize if not neurosymbolic; avoids conflict with llama.cpp check in EngineRepository.register_from_package
29
+ self.api_key = self.config["NEUROSYMBOLIC_ENGINE_API_KEY"]
30
+ self.model = self.config["NEUROSYMBOLIC_ENGINE_MODEL"]
31
31
  self.name = self.__class__.__name__
32
32
  self.tokenizer = None
33
33
  self.max_context_tokens = self.api_max_context_tokens()
@@ -37,71 +37,92 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
37
37
  try:
38
38
  self.client = OpenAI(api_key=self.api_key, base_url="https://api.deepseek.com")
39
39
  except Exception as e:
40
- UserMessage(f'Failed to initialize the DeepSeek client. Please check your library version. Caused by: {e}', raise_with=RuntimeError)
40
+ UserMessage(
41
+ f"Failed to initialize the DeepSeek client. Please check your library version. Caused by: {e}",
42
+ raise_with=RuntimeError,
43
+ )
41
44
 
42
45
  def id(self) -> str:
43
- if self.config.get('NEUROSYMBOLIC_ENGINE_MODEL') and \
44
- self.config.get('NEUROSYMBOLIC_ENGINE_MODEL').startswith('deepseek'):
45
- return 'neurosymbolic'
46
- return super().id() # default to unregistered
46
+ if self.config.get("NEUROSYMBOLIC_ENGINE_MODEL") and self.config.get(
47
+ "NEUROSYMBOLIC_ENGINE_MODEL"
48
+ ).startswith("deepseek"):
49
+ return "neurosymbolic"
50
+ return super().id() # default to unregistered
47
51
 
48
52
  def command(self, *args, **kwargs):
49
53
  super().command(*args, **kwargs)
50
- if 'NEUROSYMBOLIC_ENGINE_API_KEY' in kwargs:
51
- self.api_key = kwargs['NEUROSYMBOLIC_ENGINE_API_KEY']
52
- if 'NEUROSYMBOLIC_ENGINE_MODEL' in kwargs:
53
- self.model = kwargs['NEUROSYMBOLIC_ENGINE_MODEL']
54
- if 'seed' in kwargs:
55
- self.seed = kwargs['seed']
54
+ if "NEUROSYMBOLIC_ENGINE_API_KEY" in kwargs:
55
+ self.api_key = kwargs["NEUROSYMBOLIC_ENGINE_API_KEY"]
56
+ if "NEUROSYMBOLIC_ENGINE_MODEL" in kwargs:
57
+ self.model = kwargs["NEUROSYMBOLIC_ENGINE_MODEL"]
58
+ if "seed" in kwargs:
59
+ self.seed = kwargs["seed"]
56
60
 
57
61
  def compute_required_tokens(self, _messages):
58
- UserMessage('Method "compute_required_tokens" not implemented for DeepSeekXReasoningEngine.', raise_with=NotImplementedError)
62
+ UserMessage(
63
+ 'Method "compute_required_tokens" not implemented for DeepSeekXReasoningEngine.',
64
+ raise_with=NotImplementedError,
65
+ )
59
66
 
60
67
  def compute_remaining_tokens(self, _prompts: list) -> int:
61
- UserMessage('Method "compute_remaining_tokens" not implemented for DeepSeekXReasoningEngine.', raise_with=NotImplementedError)
62
-
63
- def truncate(self, _prompts: list[dict], _truncation_percentage: float | None, _truncation_type: str) -> list[dict]:
64
- UserMessage('Method "truncate" not implemented for DeepSeekXReasoningEngine.', raise_with=NotImplementedError)
68
+ UserMessage(
69
+ 'Method "compute_remaining_tokens" not implemented for DeepSeekXReasoningEngine.',
70
+ raise_with=NotImplementedError,
71
+ )
72
+
73
+ def truncate(
74
+ self, _prompts: list[dict], _truncation_percentage: float | None, _truncation_type: str
75
+ ) -> list[dict]:
76
+ UserMessage(
77
+ 'Method "truncate" not implemented for DeepSeekXReasoningEngine.',
78
+ raise_with=NotImplementedError,
79
+ )
65
80
 
66
81
  def forward(self, argument):
67
82
  kwargs = argument.kwargs
68
83
  messages = argument.prop.prepared_input
69
84
  payload = self._prepare_request_payload(argument)
70
- except_remedy = kwargs.get('except_remedy')
85
+ except_remedy = kwargs.get("except_remedy")
71
86
 
72
87
  try:
73
88
  res = self.client.chat.completions.create(messages=messages, **payload)
74
89
 
75
90
  except Exception as e:
76
- if self.api_key is None or self.api_key == '':
77
- msg = 'DeepSeek API key is not set. Please set it in the config file or pass it as an argument to the command method.'
91
+ if self.api_key is None or self.api_key == "":
92
+ msg = "DeepSeek API key is not set. Please set it in the config file or pass it as an argument to the command method."
78
93
  UserMessage(msg)
79
- if self.config['NEUROSYMBOLIC_ENGINE_API_KEY'] is None or self.config['NEUROSYMBOLIC_ENGINE_API_KEY'] == '':
94
+ if (
95
+ self.config["NEUROSYMBOLIC_ENGINE_API_KEY"] is None
96
+ or self.config["NEUROSYMBOLIC_ENGINE_API_KEY"] == ""
97
+ ):
80
98
  UserMessage(msg, raise_with=ValueError)
81
- self.api_key = self.config['NEUROSYMBOLIC_ENGINE_API_KEY']
99
+ self.api_key = self.config["NEUROSYMBOLIC_ENGINE_API_KEY"]
82
100
 
83
101
  callback = self.client.chat.completions.create
84
- kwargs['model'] = kwargs.get('model', self.model)
102
+ kwargs["model"] = kwargs.get("model", self.model)
85
103
 
86
104
  if except_remedy is not None:
87
105
  res = except_remedy(self, e, callback, argument)
88
106
  else:
89
- UserMessage(f'Error during generation. Caused by: {e}', raise_with=ValueError)
107
+ UserMessage(f"Error during generation. Caused by: {e}", raise_with=ValueError)
90
108
 
91
109
  reasoning_content = res.choices[0].message.reasoning_content
92
110
  content = res.choices[0].message.content
93
- metadata = {'raw_output': res, 'thinking': reasoning_content}
111
+ metadata = {"raw_output": res, "thinking": reasoning_content}
94
112
 
95
113
  return [content], metadata
96
114
 
97
115
  def _prepare_raw_input(self, argument):
98
116
  if not argument.prop.processed_input:
99
- UserMessage('A prompt instruction is required for DeepSeekXReasoningEngine when raw_input is enabled.', raise_with=ValueError)
117
+ UserMessage(
118
+ "A prompt instruction is required for DeepSeekXReasoningEngine when raw_input is enabled.",
119
+ raise_with=ValueError,
120
+ )
100
121
  value = argument.prop.processed_input
101
122
  # convert to dict if not already
102
123
  if not isinstance(value, list):
103
124
  if not isinstance(value, dict):
104
- value = {'role': 'user', 'content': str(value)}
125
+ value = {"role": "user", "content": str(value)}
105
126
  value = [value]
106
127
  return value
107
128
 
@@ -112,14 +133,17 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
112
133
 
113
134
  if prop.suppress_verbose_output:
114
135
  system += _non_verbose_output
115
- system = f'{system}\n' if system and len(system) > 0 else ''
136
+ system = f"{system}\n" if system and len(system) > 0 else ""
116
137
 
117
138
  if prop.response_format:
118
139
  _rsp_fmt = prop.response_format
119
- if not (_rsp_fmt.get('type') is not None):
120
- UserMessage('Response format type is required! Expected format `{"type": "json_object"}` or other supported types.', raise_with=AssertionError)
140
+ if not (_rsp_fmt.get("type") is not None):
141
+ UserMessage(
142
+ 'Response format type is required! Expected format `{"type": "json_object"}` or other supported types.',
143
+ raise_with=AssertionError,
144
+ )
121
145
  system += _non_verbose_output
122
- system += f'<RESPONSE_FORMAT/>\n{_rsp_fmt["type"]}\n\n'
146
+ system += f"<RESPONSE_FORMAT/>\n{_rsp_fmt['type']}\n\n"
123
147
 
124
148
  ref = prop.instance
125
149
  static_ctxt, dyn_ctxt = ref.global_context
@@ -142,7 +166,7 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
142
166
  system += f"<INSTRUCTION/>\n{val}\n\n"
143
167
 
144
168
  if prop.template_suffix:
145
- system += f' You will only generate content for the placeholder `{prop.template_suffix!s}` following the instructions and the provided context information.\n\n'
169
+ system += f" You will only generate content for the placeholder `{prop.template_suffix!s}` following the instructions and the provided context information.\n\n"
146
170
 
147
171
  return system
148
172
 
@@ -151,15 +175,17 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
151
175
 
152
176
  def _apply_self_prompt(self, argument, system, user_prompt):
153
177
  prop = argument.prop
154
- if prop.instance._kwargs.get('self_prompt', False) or prop.self_prompt:
178
+ if prop.instance._kwargs.get("self_prompt", False) or prop.self_prompt:
155
179
  self_prompter = SelfPrompt()
156
180
 
157
- res = self_prompter({'user': user_prompt['content'], 'system': system})
181
+ res = self_prompter({"user": user_prompt["content"], "system": system})
158
182
  if res is None:
159
- UserMessage("Self-prompting failed for DeepSeekXReasoningEngine.", raise_with=ValueError)
183
+ UserMessage(
184
+ "Self-prompting failed for DeepSeekXReasoningEngine.", raise_with=ValueError
185
+ )
160
186
 
161
- user_prompt = { "role": "user", "content": res['user'] }
162
- system = res['system']
187
+ user_prompt = {"role": "user", "content": res["user"]}
188
+ system = res["system"]
163
189
 
164
190
  return system, user_prompt
165
191
 
@@ -173,7 +199,7 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
173
199
  system, user_prompt = self._apply_self_prompt(argument, system, user_prompt)
174
200
 
175
201
  argument.prop.prepared_input = [
176
- { "role": "system", "content": system },
202
+ {"role": "system", "content": system},
177
203
  user_prompt,
178
204
  ]
179
205
 
@@ -184,10 +210,10 @@ class DeepSeekXReasoningEngine(Engine, DeepSeekMixin):
184
210
  # Not Supported Features: Function Call、Json Output、FIM (Beta)
185
211
  # Not Supported Parameters: temperature、top_p、presence_penalty、frequency_penalty、logprobs、top_logprobs
186
212
  return {
187
- "model": kwargs.get('model', self.model),
188
- "seed": kwargs.get('seed', self.seed),
189
- "max_tokens": kwargs.get('max_tokens', self.max_response_tokens),
190
- "stop": kwargs.get('stop', '<|endoftext|>'),
191
- "n": kwargs.get('n', 1),
192
- "logit_bias": kwargs.get('logit_bias'),
213
+ "model": kwargs.get("model", self.model),
214
+ "seed": kwargs.get("seed", self.seed),
215
+ "max_tokens": kwargs.get("max_tokens", self.max_response_tokens),
216
+ "stop": kwargs.get("stop", "<|endoftext|>"),
217
+ "n": kwargs.get("n", 1),
218
+ "logit_bias": kwargs.get("logit_bias"),
193
219
  }