symbolicai 0.21.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. symai/__init__.py +269 -173
  2. symai/backend/base.py +123 -110
  3. symai/backend/engines/drawing/engine_bfl.py +45 -44
  4. symai/backend/engines/drawing/engine_gpt_image.py +112 -97
  5. symai/backend/engines/embedding/engine_llama_cpp.py +63 -52
  6. symai/backend/engines/embedding/engine_openai.py +25 -21
  7. symai/backend/engines/execute/engine_python.py +19 -18
  8. symai/backend/engines/files/engine_io.py +104 -95
  9. symai/backend/engines/imagecaptioning/engine_blip2.py +28 -24
  10. symai/backend/engines/imagecaptioning/engine_llavacpp_client.py +102 -79
  11. symai/backend/engines/index/engine_pinecone.py +124 -97
  12. symai/backend/engines/index/engine_qdrant.py +1011 -0
  13. symai/backend/engines/index/engine_vectordb.py +84 -56
  14. symai/backend/engines/lean/engine_lean4.py +96 -52
  15. symai/backend/engines/neurosymbolic/__init__.py +41 -13
  16. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_chat.py +330 -248
  17. symai/backend/engines/neurosymbolic/engine_anthropic_claudeX_reasoning.py +329 -264
  18. symai/backend/engines/neurosymbolic/engine_cerebras.py +328 -0
  19. symai/backend/engines/neurosymbolic/engine_deepseekX_reasoning.py +118 -88
  20. symai/backend/engines/neurosymbolic/engine_google_geminiX_reasoning.py +344 -299
  21. symai/backend/engines/neurosymbolic/engine_groq.py +173 -115
  22. symai/backend/engines/neurosymbolic/engine_huggingface.py +114 -84
  23. symai/backend/engines/neurosymbolic/engine_llama_cpp.py +144 -118
  24. symai/backend/engines/neurosymbolic/engine_openai_gptX_chat.py +415 -307
  25. symai/backend/engines/neurosymbolic/engine_openai_gptX_reasoning.py +394 -231
  26. symai/backend/engines/ocr/engine_apilayer.py +23 -27
  27. symai/backend/engines/output/engine_stdout.py +10 -13
  28. symai/backend/engines/{webscraping → scrape}/engine_requests.py +101 -54
  29. symai/backend/engines/search/engine_openai.py +100 -88
  30. symai/backend/engines/search/engine_parallel.py +665 -0
  31. symai/backend/engines/search/engine_perplexity.py +44 -45
  32. symai/backend/engines/search/engine_serpapi.py +37 -34
  33. symai/backend/engines/speech_to_text/engine_local_whisper.py +54 -51
  34. symai/backend/engines/symbolic/engine_wolframalpha.py +15 -9
  35. symai/backend/engines/text_to_speech/engine_openai.py +20 -26
  36. symai/backend/engines/text_vision/engine_clip.py +39 -37
  37. symai/backend/engines/userinput/engine_console.py +5 -6
  38. symai/backend/mixin/__init__.py +13 -0
  39. symai/backend/mixin/anthropic.py +48 -38
  40. symai/backend/mixin/deepseek.py +6 -5
  41. symai/backend/mixin/google.py +7 -4
  42. symai/backend/mixin/groq.py +2 -4
  43. symai/backend/mixin/openai.py +140 -110
  44. symai/backend/settings.py +87 -20
  45. symai/chat.py +216 -123
  46. symai/collect/__init__.py +7 -1
  47. symai/collect/dynamic.py +80 -70
  48. symai/collect/pipeline.py +67 -51
  49. symai/collect/stats.py +161 -109
  50. symai/components.py +707 -360
  51. symai/constraints.py +24 -12
  52. symai/core.py +1857 -1233
  53. symai/core_ext.py +83 -80
  54. symai/endpoints/api.py +166 -104
  55. symai/extended/.DS_Store +0 -0
  56. symai/extended/__init__.py +46 -12
  57. symai/extended/api_builder.py +29 -21
  58. symai/extended/arxiv_pdf_parser.py +23 -14
  59. symai/extended/bibtex_parser.py +9 -6
  60. symai/extended/conversation.py +156 -126
  61. symai/extended/document.py +50 -30
  62. symai/extended/file_merger.py +57 -14
  63. symai/extended/graph.py +51 -32
  64. symai/extended/html_style_template.py +18 -14
  65. symai/extended/interfaces/blip_2.py +2 -3
  66. symai/extended/interfaces/clip.py +4 -3
  67. symai/extended/interfaces/console.py +9 -1
  68. symai/extended/interfaces/dall_e.py +4 -2
  69. symai/extended/interfaces/file.py +2 -0
  70. symai/extended/interfaces/flux.py +4 -2
  71. symai/extended/interfaces/gpt_image.py +16 -7
  72. symai/extended/interfaces/input.py +2 -1
  73. symai/extended/interfaces/llava.py +1 -2
  74. symai/extended/interfaces/{naive_webscraping.py → naive_scrape.py} +4 -3
  75. symai/extended/interfaces/naive_vectordb.py +9 -10
  76. symai/extended/interfaces/ocr.py +5 -3
  77. symai/extended/interfaces/openai_search.py +2 -0
  78. symai/extended/interfaces/parallel.py +30 -0
  79. symai/extended/interfaces/perplexity.py +2 -0
  80. symai/extended/interfaces/pinecone.py +12 -9
  81. symai/extended/interfaces/python.py +2 -0
  82. symai/extended/interfaces/serpapi.py +3 -1
  83. symai/extended/interfaces/terminal.py +2 -4
  84. symai/extended/interfaces/tts.py +3 -2
  85. symai/extended/interfaces/whisper.py +3 -2
  86. symai/extended/interfaces/wolframalpha.py +2 -1
  87. symai/extended/metrics/__init__.py +11 -1
  88. symai/extended/metrics/similarity.py +14 -13
  89. symai/extended/os_command.py +39 -29
  90. symai/extended/packages/__init__.py +29 -3
  91. symai/extended/packages/symdev.py +51 -43
  92. symai/extended/packages/sympkg.py +41 -35
  93. symai/extended/packages/symrun.py +63 -50
  94. symai/extended/repo_cloner.py +14 -12
  95. symai/extended/seo_query_optimizer.py +15 -13
  96. symai/extended/solver.py +116 -91
  97. symai/extended/summarizer.py +12 -10
  98. symai/extended/taypan_interpreter.py +17 -18
  99. symai/extended/vectordb.py +122 -92
  100. symai/formatter/__init__.py +9 -1
  101. symai/formatter/formatter.py +51 -47
  102. symai/formatter/regex.py +70 -69
  103. symai/functional.py +325 -176
  104. symai/imports.py +190 -147
  105. symai/interfaces.py +57 -28
  106. symai/memory.py +45 -35
  107. symai/menu/screen.py +28 -19
  108. symai/misc/console.py +66 -56
  109. symai/misc/loader.py +8 -5
  110. symai/models/__init__.py +17 -1
  111. symai/models/base.py +395 -236
  112. symai/models/errors.py +1 -2
  113. symai/ops/__init__.py +32 -22
  114. symai/ops/measures.py +24 -25
  115. symai/ops/primitives.py +1149 -731
  116. symai/post_processors.py +58 -50
  117. symai/pre_processors.py +86 -82
  118. symai/processor.py +21 -13
  119. symai/prompts.py +764 -685
  120. symai/server/huggingface_server.py +135 -49
  121. symai/server/llama_cpp_server.py +21 -11
  122. symai/server/qdrant_server.py +206 -0
  123. symai/shell.py +100 -42
  124. symai/shellsv.py +700 -492
  125. symai/strategy.py +630 -346
  126. symai/symbol.py +368 -322
  127. symai/utils.py +100 -78
  128. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/METADATA +22 -10
  129. symbolicai-1.1.0.dist-info/RECORD +168 -0
  130. symbolicai-0.21.0.dist-info/RECORD +0 -162
  131. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/WHEEL +0 -0
  132. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/entry_points.txt +0 -0
  133. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/licenses/LICENSE +0 -0
  134. {symbolicai-0.21.0.dist-info → symbolicai-1.1.0.dist-info}/top_level.txt +0 -0
@@ -1,39 +1,38 @@
1
1
  import logging
2
- import requests
2
+ from io import BytesIO
3
3
 
4
+ import requests
4
5
  import torch
5
- from typing import Optional
6
6
  from PIL import Image
7
- from io import BytesIO
8
7
  from transformers import CLIPModel, CLIPProcessor
9
8
 
9
+ from ....utils import UserMessage
10
10
  from ...base import Engine
11
11
  from ...settings import SYMAI_CONFIG
12
12
 
13
-
14
13
  # supress warnings
15
14
  logging.getLogger("PIL").setLevel(logging.WARNING)
16
15
 
17
16
 
18
17
  class CLIPEngine(Engine):
19
- def __init__(self, model: Optional[str] = None):
18
+ def __init__(self, model: str | None = None):
20
19
  super().__init__()
21
- self.model = None # lazy loading
22
- self.preprocessor = None # lazy loading
20
+ self.model = None # lazy loading
21
+ self.preprocessor = None # lazy loading
23
22
  self.config = SYMAI_CONFIG
24
- self.model_id = self.config['VISION_ENGINE_MODEL'] if model is None else model
25
- self.old_model_id = self.config['VISION_ENGINE_MODEL'] if model is None else model
23
+ self.model_id = self.config["VISION_ENGINE_MODEL"] if model is None else model
24
+ self.old_model_id = self.config["VISION_ENGINE_MODEL"] if model is None else model
26
25
  self.name = self.__class__.__name__
27
26
 
28
27
  def id(self) -> str:
29
- if self.config['VISION_ENGINE_MODEL']:
30
- return 'text_vision'
31
- return super().id() # default to unregistered
28
+ if self.config["VISION_ENGINE_MODEL"]:
29
+ return "text_vision"
30
+ return super().id() # default to unregistered
32
31
 
33
32
  def command(self, *args, **kwargs):
34
33
  super().command(*args, **kwargs)
35
- if 'VISION_ENGINE_MODEL' in kwargs:
36
- self.model_id = kwargs['VISION_ENGINE_MODEL']
34
+ if "VISION_ENGINE_MODEL" in kwargs:
35
+ self.model_id = kwargs["VISION_ENGINE_MODEL"]
37
36
 
38
37
  def load_images(self, image):
39
38
  images = []
@@ -44,38 +43,41 @@ class CLIPEngine(Engine):
44
43
  if isinstance(img, bytes):
45
44
  images.append(Image.open(BytesIO(img)))
46
45
  elif isinstance(img, str):
47
- if img.startswith('http'):
48
- image_ = requests.get(img, stream=True).raw
49
- else:
50
- image_ = img
51
- image = Image.open(image_)
46
+ image_source = requests.get(img, stream=True).raw if img.startswith("http") else img
47
+ image = Image.open(image_source)
52
48
  images.append(image)
53
49
  return images
54
50
 
55
51
  def forward(self, argument):
56
- image_url, text = argument.prop.prepared_input
52
+ image_url, text = argument.prop.prepared_input
57
53
 
58
54
  if self.model is None or self.model_id != self.old_model_id:
59
- self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
60
- self.model = CLIPModel.from_pretrained(self.model_id).to(self.device)
61
- self.processor = CLIPProcessor.from_pretrained(self.model_id)
55
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
56
+ self.model = CLIPModel.from_pretrained(self.model_id).to(self.device)
57
+ self.processor = CLIPProcessor.from_pretrained(self.model_id)
62
58
  self.old_model_id = self.model_id
63
59
 
64
60
  if text is None and image_url is not None:
65
- image = self.load_images(image_url)
66
- inputs = self.processor(images=image, return_tensors="pt").to(self.device)
67
- rsp = self.model.get_image_features(**inputs)
61
+ image = self.load_images(image_url)
62
+ inputs = self.processor(images=image, return_tensors="pt").to(self.device)
63
+ rsp = self.model.get_image_features(**inputs)
68
64
  elif image_url is None and text is not None:
69
- inputs = self.processor(text=text, return_tensors="pt").to(self.device)
70
- rsp = self.model.get_text_features(**inputs)
65
+ inputs = self.processor(text=text, return_tensors="pt").to(self.device)
66
+ rsp = self.model.get_text_features(**inputs)
71
67
  elif image_url is not None and text is not None:
72
- image = self.load_images(image_url)
73
- inputs = self.processor(text=text, images=image, return_tensors="pt", padding=True).to(self.device)
74
- outputs = self.model(**inputs)
75
- logits_per_image = outputs.logits_per_image # this is the image-text similarity score
76
- rsp = logits_per_image.softmax(dim=1) # we can take the softmax to get the label probabilities
68
+ image = self.load_images(image_url)
69
+ inputs = self.processor(text=text, images=image, return_tensors="pt", padding=True).to(
70
+ self.device
71
+ )
72
+ outputs = self.model(**inputs)
73
+ logits_per_image = outputs.logits_per_image # this is the image-text similarity score
74
+ rsp = logits_per_image.softmax(
75
+ dim=1
76
+ ) # we can take the softmax to get the label probabilities
77
77
  else:
78
- raise NotImplementedError("CLIPEngine requires either image or text input.")
78
+ UserMessage(
79
+ "CLIPEngine requires either image or text input.", raise_with=NotImplementedError
80
+ )
79
81
 
80
82
  rsp = rsp.squeeze().detach().cpu().numpy()
81
83
 
@@ -85,7 +87,7 @@ class CLIPEngine(Engine):
85
87
 
86
88
  def prepare(self, argument):
87
89
  assert not argument.prop.processed_input, "CLIPEngine does not support processed_input."
88
- kwargs = argument.kwargs
89
- image_url = argument.kwargs['image'] if 'image' in kwargs else None
90
- text = argument.kwargs['text'] if 'text' in kwargs else None
90
+ kwargs = argument.kwargs
91
+ image_url = argument.kwargs["image"] if "image" in kwargs else None
92
+ text = argument.kwargs["text"] if "text" in kwargs else None
91
93
  argument.prop.prepared_input = (image_url, text)
@@ -1,5 +1,4 @@
1
- from typing import List
2
-
1
+ from ....utils import UserMessage
3
2
  from ...base import Engine
4
3
 
5
4
 
@@ -9,15 +8,15 @@ class UserInputEngine(Engine):
9
8
  self.name = self.__class__.__name__
10
9
 
11
10
  def id(self) -> str:
12
- return 'userinput'
11
+ return "userinput"
13
12
 
14
13
  def forward(self, argument):
15
14
  msg = argument.prop.prepared_input
16
15
  kwargs = argument.kwargs
17
16
 
18
- mock = kwargs['mock'] if 'mock' in kwargs else False
19
- if mock: # mock user input
20
- print(msg, end='') # print prompt
17
+ mock = kwargs.get("mock", False)
18
+ if mock: # mock user input
19
+ UserMessage(msg)
21
20
  rsp = mock
22
21
  else:
23
22
  rsp = input(msg)
@@ -8,3 +8,16 @@ from .groq import SUPPORTED_CHAT_MODELS as GROQ_CHAT_MODELS
8
8
  from .groq import SUPPORTED_REASONING_MODELS as GROQ_REASONING_MODELS
9
9
  from .openai import SUPPORTED_CHAT_MODELS as OPENAI_CHAT_MODELS
10
10
  from .openai import SUPPORTED_REASONING_MODELS as OPENAI_REASONING_MODELS
11
+
12
+ __all__ = [
13
+ "ANTHROPIC_CHAT_MODELS",
14
+ "ANTHROPIC_REASONING_MODELS",
15
+ "DEEPSEEK_CHAT_MODELS",
16
+ "DEEPSEEK_REASONING_MODELS",
17
+ "GOOGLE_CHAT_MODELS",
18
+ "GOOGLE_REASONING_MODELS",
19
+ "GROQ_CHAT_MODELS",
20
+ "GROQ_REASONING_MODELS",
21
+ "OPENAI_CHAT_MODELS",
22
+ "OPENAI_REASONING_MODELS",
23
+ ]
@@ -1,56 +1,66 @@
1
1
  # https://docs.anthropic.com/en/docs/about-claude/models
2
2
  SUPPORTED_CHAT_MODELS = [
3
- 'claude-3-5-sonnet-latest',
4
- 'claude-3-5-haiku-latest',
5
- 'claude-3-5-sonnet-20241022',
6
- 'claude-3-5-sonnet-20240620',
7
- 'claude-3-opus-latest',
8
- 'claude-3-opus-20240229',
9
- 'claude-3-sonnet-20240229',
10
- 'claude-3-haiku-20240307',
3
+ "claude-3-5-sonnet-latest",
4
+ "claude-3-5-haiku-latest",
5
+ "claude-3-5-sonnet-20241022",
6
+ "claude-3-5-sonnet-20240620",
7
+ "claude-3-opus-latest",
8
+ "claude-3-opus-20240229",
9
+ "claude-3-sonnet-20240229",
10
+ "claude-3-haiku-20240307",
11
11
  ]
12
12
  SUPPORTED_REASONING_MODELS = [
13
13
  "claude-opus-4-1",
14
14
  "claude-opus-4-0",
15
15
  "claude-sonnet-4-0",
16
- 'claude-3-7-sonnet-latest',
17
- 'claude-haiku-4-5',
18
- 'claude-sonnet-4-5',
16
+ "claude-3-7-sonnet-latest",
17
+ "claude-haiku-4-5",
18
+ "claude-sonnet-4-5",
19
19
  ]
20
20
 
21
+
21
22
  class AnthropicMixin:
22
23
  def api_max_context_tokens(self):
23
- if self.model == 'claude-opus-4-1' or \
24
- self.model == 'claude-opus-4-0' or \
25
- self.model == 'claude-sonnet-4-0' or \
26
- self.model == 'claude-3-7-sonnet-latest' or \
27
- self.model == 'claude-haiku-4-5' or \
28
- self.model == 'claude-sonnet-4-5' or \
29
- self.model == 'claude-3-5-sonnet-latest' or \
30
- self.model == 'claude-3-5-sonnet-20241022' or \
31
- self.model == 'claude-3-5-sonnet-20240620' or \
32
- self.model == 'claude-3-opus-latest' or \
33
- self.model == 'claude-3-opus-20240229' or \
34
- self.model == 'claude-3-sonnet-20240229' or \
35
- self.model == 'claude-3-haiku-20240307':
24
+ if (
25
+ self.model == "claude-opus-4-1"
26
+ or self.model == "claude-opus-4-0"
27
+ or self.model == "claude-sonnet-4-0"
28
+ or self.model == "claude-3-7-sonnet-latest"
29
+ or self.model == "claude-haiku-4-5"
30
+ or self.model == "claude-sonnet-4-5"
31
+ or self.model == "claude-3-5-sonnet-latest"
32
+ or self.model == "claude-3-5-sonnet-20241022"
33
+ or self.model == "claude-3-5-sonnet-20240620"
34
+ or self.model == "claude-3-opus-latest"
35
+ or self.model == "claude-3-opus-20240229"
36
+ or self.model == "claude-3-sonnet-20240229"
37
+ or self.model == "claude-3-haiku-20240307"
38
+ ):
36
39
  return 200_000
40
+ return None
37
41
 
38
42
  def api_max_response_tokens(self):
39
- if self.model == 'claude-sonnet-4-0' or \
40
- self.model == 'claude-3-7-sonnet-latest' or \
41
- self.model == 'claude-haiku-4-5' or \
42
- self.model == 'claude-sonnet-4-5':
43
+ if (
44
+ self.model == "claude-sonnet-4-0"
45
+ or self.model == "claude-3-7-sonnet-latest"
46
+ or self.model == "claude-haiku-4-5"
47
+ or self.model == "claude-sonnet-4-5"
48
+ ):
43
49
  return 64_000
44
- if self.model == 'claude-opus-4-1' or \
45
- self.model == 'claude-opus-4-0':
50
+ if self.model == "claude-opus-4-1" or self.model == "claude-opus-4-0":
46
51
  return 32_000
47
- if self.model == 'claude-3-5-sonnet-latest' or \
48
- self.model == 'claude-3-5-sonnet-20241022' or \
49
- self.model == 'claude-3-5-haiku-latest':
52
+ if (
53
+ self.model == "claude-3-5-sonnet-latest"
54
+ or self.model == "claude-3-5-sonnet-20241022"
55
+ or self.model == "claude-3-5-haiku-latest"
56
+ ):
50
57
  return 8_192
51
- if self.model == 'claude-3-5-sonnet-20240620' or \
52
- self.model == 'claude-3-opus-latest' or \
53
- self.model == 'clade-3-opus-20240229' or \
54
- self.model == 'claude-3-sonnet-20240229' or \
55
- self.model == 'claude-3-haiku-20240307':
58
+ if (
59
+ self.model == "claude-3-5-sonnet-20240620"
60
+ or self.model == "claude-3-opus-latest"
61
+ or self.model == "clade-3-opus-20240229"
62
+ or self.model == "claude-3-sonnet-20240229"
63
+ or self.model == "claude-3-haiku-20240307"
64
+ ):
56
65
  return 4_096
66
+ return None
@@ -1,14 +1,15 @@
1
1
  # https://api-docs.deepseek.com/quick_start/pricing
2
2
  SUPPORTED_CHAT_MODELS = []
3
- SUPPORTED_REASONING_MODELS = [
4
- 'deepseek-reasoner'
5
- ]
3
+ SUPPORTED_REASONING_MODELS = ["deepseek-reasoner"]
4
+
6
5
 
7
6
  class DeepSeekMixin:
8
7
  def api_max_context_tokens(self):
9
- if self.model == 'deepseek-reasoner':
8
+ if self.model == "deepseek-reasoner":
10
9
  return 64_000
10
+ return None
11
11
 
12
12
  def api_max_response_tokens(self):
13
- if self.model == 'deepseek-reasoner':
13
+ if self.model == "deepseek-reasoner":
14
14
  return 8_000
15
+ return None
@@ -2,15 +2,18 @@
2
2
  SUPPORTED_CHAT_MODELS = []
3
3
  SUPPORTED_REASONING_MODELS = [
4
4
  # Check the latest snapshots; ie. *-06-05, etc
5
- 'gemini-2.5-pro',
6
- 'gemini-2.5-flash',
5
+ "gemini-2.5-pro",
6
+ "gemini-2.5-flash",
7
7
  ]
8
8
 
9
+
9
10
  class GoogleMixin:
10
11
  def api_max_context_tokens(self):
11
- if self.model.startswith('gemini-2.5-'):
12
+ if self.model.startswith("gemini-2.5-"):
12
13
  return 1_048_576
14
+ return None
13
15
 
14
16
  def api_max_response_tokens(self):
15
- if self.model == 'gemini-2.5-':
17
+ if self.model == "gemini-2.5-":
16
18
  return 65_536
19
+ return None
@@ -1,10 +1,8 @@
1
- SUPPORTED_CHAT_MODELS = [
2
- "groq:moonshotai/kimi-k2-instruct"
3
- ]
1
+ SUPPORTED_CHAT_MODELS = ["groq:moonshotai/kimi-k2-instruct"]
4
2
 
5
3
  SUPPORTED_REASONING_MODELS = [
6
4
  "groq:openai/gpt-oss-120b",
7
5
  "groq:openai/gpt-oss-20b",
8
6
  "groq:qwen/qwen3-32b",
9
- "groq:deepseek-r1-distill-llama-70b"
7
+ "groq:deepseek-r1-distill-llama-70b",
10
8
  ]
@@ -1,134 +1,164 @@
1
+ from ...utils import UserMessage
2
+
1
3
  SUPPORTED_COMPLETION_MODELS = [
2
- 'davinci-002',
4
+ "davinci-002",
3
5
  ]
4
6
  SUPPORTED_CHAT_MODELS = [
5
- 'gpt-3.5-turbo',
6
- 'gpt-3.5-turbo-16k',
7
- 'gpt-3.5-turbo-1106',
8
- 'gpt-3.5-turbo-0613',
9
- 'gpt-4',
10
- 'gpt-4-0613',
11
- 'gpt-4-1106-preview', # @NOTE: probabily obsolete; same price as 'gpt-4-turbo-2024-04-09' but no vision
12
- 'gpt-4-turbo',
13
- 'gpt-4-turbo-2024-04-09',
14
- 'gpt-4o',
15
- 'gpt-4o-2024-11-20',
16
- 'gpt-4o-mini',
17
- 'chatgpt-4o-latest',
18
- 'gpt-4.1',
19
- 'gpt-4.1-mini',
20
- 'gpt-4.1-nano',
21
- 'gpt-5-chat-latest',
7
+ "gpt-3.5-turbo",
8
+ "gpt-3.5-turbo-16k",
9
+ "gpt-3.5-turbo-1106",
10
+ "gpt-3.5-turbo-0613",
11
+ "gpt-4",
12
+ "gpt-4-0613",
13
+ "gpt-4-1106-preview", # @NOTE: probabily obsolete; same price as 'gpt-4-turbo-2024-04-09' but no vision
14
+ "gpt-4-turbo",
15
+ "gpt-4-turbo-2024-04-09",
16
+ "gpt-4o",
17
+ "gpt-4o-2024-11-20",
18
+ "gpt-4o-mini",
19
+ "chatgpt-4o-latest",
20
+ "gpt-4.1",
21
+ "gpt-4.1-mini",
22
+ "gpt-4.1-nano",
23
+ "gpt-5-chat-latest",
24
+ "gpt-5.1-chat-latest",
22
25
  ]
23
26
  SUPPORTED_REASONING_MODELS = [
24
- 'o3-mini',
25
- 'o4-mini',
26
- 'o1',
27
- 'o3',
28
- 'gpt-5',
29
- 'gpt-5-mini',
30
- 'gpt-5-nano',
27
+ "o3-mini",
28
+ "o4-mini",
29
+ "o1",
30
+ "o3",
31
+ "gpt-5",
32
+ "gpt-5.1",
33
+ "gpt-5-mini",
34
+ "gpt-5-nano",
31
35
  ]
32
36
  SUPPORTED_EMBEDDING_MODELS = [
33
- 'text-embedding-ada-002',
34
- 'text-embedding-3-small',
35
- 'text-embedding-3-large'
37
+ "text-embedding-ada-002",
38
+ "text-embedding-3-small",
39
+ "text-embedding-3-large",
36
40
  ]
37
41
 
38
42
 
39
43
  class OpenAIMixin:
40
44
  def api_max_context_tokens(self):
41
- if self.model == 'text-curie-001' or \
42
- self.model == 'text-babbage-001' or \
43
- self.model == 'text-ada-001' or \
44
- self.model == 'davinci' or \
45
- self.model == 'curie' or \
46
- self.model == 'babbage' or \
47
- self.model == 'ada':
48
- return 2_049
49
- if self.model == 'gpt-3.5-turbo' or \
50
- self.model == 'gpt-3.5-turbo-0613' or \
51
- self.model == 'gpt-3.5-turbo-1106':
52
- return 4_096
53
- if self.model == 'gpt-4' or \
54
- self.model == 'gpt-4-0613' or \
55
- self.model == 'text-embedding-ada-002' or \
56
- self.model == 'text-embedding-3-small' or \
57
- self.model == 'text-embedding-3-large':
58
- return 8_192
59
- if self.model == 'gpt-3.5-turbo-16k' or \
60
- self.model == 'gpt-3.5-turbo-16k-0613' or \
61
- self.model == 'davinci-002':
62
- return 16_384
63
- if self.model == 'gpt-4-32k' or \
64
- self.model == 'gpt-4-32k-0613':
65
- return 32_768
66
- if self.model == 'gpt-4-1106-preview' or \
67
- self.model == 'gpt-4-turbo-2024-04-09' or \
68
- self.model == 'gpt-4-turbo' or \
69
- self.model == 'gpt-4-1106' or \
70
- self.model == 'gpt-4o' or \
71
- self.model == 'gpt-4o-2024-11-20' or \
72
- self.model == 'gpt-4o-mini' or \
73
- self.model == 'chatgpt-4o-latest':
74
- return 128_000
75
- if self.model == 'o1' or \
76
- self.model == 'o3' or \
77
- self.model == 'o3-mini' or \
78
- self.model == 'o4-mini':
79
- return 200_000
80
- if self.model == 'gpt-5' or \
81
- self.model == 'gpt-5-mini' or \
82
- self.model == 'gpt-5-nano' or \
83
- self.model == 'gpt-5-chat-latest':
45
+ if (
46
+ self.model == "text-curie-001"
47
+ or self.model == "text-babbage-001"
48
+ or self.model == "text-ada-001"
49
+ or self.model == "davinci"
50
+ or self.model == "curie"
51
+ or self.model == "babbage"
52
+ or self.model == "ada"
53
+ ):
54
+ return 2_049
55
+ if (
56
+ self.model == "gpt-3.5-turbo"
57
+ or self.model == "gpt-3.5-turbo-0613"
58
+ or self.model == "gpt-3.5-turbo-1106"
59
+ ):
60
+ return 4_096
61
+ if (
62
+ self.model == "gpt-4"
63
+ or self.model == "gpt-4-0613"
64
+ or self.model == "text-embedding-ada-002"
65
+ or self.model == "text-embedding-3-small"
66
+ or self.model == "text-embedding-3-large"
67
+ ):
68
+ return 8_192
69
+ if (
70
+ self.model == "gpt-3.5-turbo-16k"
71
+ or self.model == "gpt-3.5-turbo-16k-0613"
72
+ or self.model == "davinci-002"
73
+ ):
74
+ return 16_384
75
+ if self.model == "gpt-4-32k" or self.model == "gpt-4-32k-0613":
76
+ return 32_768
77
+ if (
78
+ self.model == "gpt-4-1106-preview"
79
+ or self.model == "gpt-4-turbo-2024-04-09"
80
+ or self.model == "gpt-4-turbo"
81
+ or self.model == "gpt-4-1106"
82
+ or self.model == "gpt-4o"
83
+ or self.model == "gpt-4o-2024-11-20"
84
+ or self.model == "gpt-4o-mini"
85
+ or self.model == "chatgpt-4o-latest"
86
+ ):
87
+ return 128_000
88
+ if (
89
+ self.model == "o1"
90
+ or self.model == "o3"
91
+ or self.model == "o3-mini"
92
+ or self.model == "o4-mini"
93
+ or self.model == "gpt-5-chat-latest"
94
+ or self.model == "gpt-5.1-chat-latest"
95
+ ):
96
+ return 200_000
97
+ if (
98
+ self.model == "gpt-5"
99
+ or self.model == "gpt-5.1"
100
+ or self.model == "gpt-5-mini"
101
+ or self.model == "gpt-5-nano"
102
+ ):
84
103
  return 400_000
85
- if self.model == 'gpt-4.1' or \
86
- self.model == 'gpt-4.1-mini' or \
87
- self.model == 'gpt-4.1-nano':
104
+ if self.model == "gpt-4.1" or self.model == "gpt-4.1-mini" or self.model == "gpt-4.1-nano":
88
105
  return 1_047_576
89
- raise ValueError(f'Unsupported model: {self.model}')
106
+ msg = f"Unsupported model: {self.model}"
107
+ UserMessage(msg)
108
+ raise ValueError(msg)
90
109
 
91
110
  def api_max_response_tokens(self):
92
- if self.model == 'davinci-002':
111
+ if self.model == "davinci-002":
93
112
  return 2_048
94
- if self.model == 'gpt-4-turbo' or \
95
- self.model == 'gpt-4-turbo-2024-04-09' or \
96
- self.model == 'gpt-4-1106-preview' or \
97
- self.model == 'gpt-3.5-turbo-1106' or \
98
- self.model == 'gpt-3.5-turbo-0613' or \
99
- self.model == 'gpt-3.5-turbo':
100
- return 4_096
101
- if self.model == 'gpt-4-0613' or \
102
- self.model == 'gpt-4':
103
- return 8_192
104
- if self.model == 'gpt-3.5-turbo-16k-0613' or \
105
- self.model == 'gpt-3.5-turbo-16k' or \
106
- self.model == 'gpt-4o-mini' or \
107
- self.model == 'gpt-4o' or \
108
- self.model == 'gpt-4o-2024-11-20' or \
109
- self.model == 'chatgpt-4o-latest':
110
- return 16_384
111
- if self.model == 'gpt-4.1' or \
112
- self.model == 'gpt-4.1-mini' or \
113
- self.model == 'gpt-4.1-nano':
113
+ if (
114
+ self.model == "gpt-4-turbo"
115
+ or self.model == "gpt-4-turbo-2024-04-09"
116
+ or self.model == "gpt-4-1106-preview"
117
+ or self.model == "gpt-3.5-turbo-1106"
118
+ or self.model == "gpt-3.5-turbo-0613"
119
+ or self.model == "gpt-3.5-turbo"
120
+ ):
121
+ return 4_096
122
+ if self.model == "gpt-4-0613" or self.model == "gpt-4":
123
+ return 8_192
124
+ if (
125
+ self.model == "gpt-3.5-turbo-16k-0613"
126
+ or self.model == "gpt-3.5-turbo-16k"
127
+ or self.model == "gpt-4o-mini"
128
+ or self.model == "gpt-4o"
129
+ or self.model == "gpt-4o-2024-11-20"
130
+ or self.model == "chatgpt-4o-latest"
131
+ or self.model == "gpt-5-chat-latest"
132
+ or self.model == "gpt-5.1-chat-latest"
133
+ ):
134
+ return 16_384
135
+ if self.model == "gpt-4.1" or self.model == "gpt-4.1-mini" or self.model == "gpt-4.1-nano":
114
136
  return 32_768
115
- if self.model == 'o1' or \
116
- self.model == 'o3' or \
117
- self.model == 'o3-mini' or \
118
- self.model == 'o4-mini':
119
- return 100_000
120
- if self.model == 'gpt-5' or \
121
- self.model == 'gpt-5-mini' or \
122
- self.model == 'gpt-5-nano' or \
123
- self.model == 'gpt-5-chat-latest':
137
+ if (
138
+ self.model == "o1"
139
+ or self.model == "o3"
140
+ or self.model == "o3-mini"
141
+ or self.model == "o4-mini"
142
+ ):
143
+ return 100_000
144
+ if (
145
+ self.model == "gpt-5"
146
+ or self.model == "gpt-5.1"
147
+ or self.model == "gpt-5-mini"
148
+ or self.model == "gpt-5-nano"
149
+ ):
124
150
  return 128_000
125
- raise ValueError(f'Unsupported model: {self.model}')
151
+ msg = f"Unsupported model: {self.model}"
152
+ UserMessage(msg)
153
+ raise ValueError(msg)
126
154
 
127
155
  def api_embedding_dims(self):
128
- if self.model == 'text-embedding-ada-002':
156
+ if self.model == "text-embedding-ada-002":
129
157
  return 1_536
130
- if self.model == 'text-embedding-3-small':
158
+ if self.model == "text-embedding-3-small":
131
159
  return 1_536
132
- if self.model == 'text-embedding-3-large':
160
+ if self.model == "text-embedding-3-large":
133
161
  return 3_072
134
- raise ValueError(f'Unsupported model: {self.model}')
162
+ msg = f"Unsupported model: {self.model}"
163
+ UserMessage(msg)
164
+ raise ValueError(msg)