synth-ai 0.1.0.dev13__py3-none-any.whl → 0.1.0.dev15__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.

Potentially problematic release.


This version of synth-ai might be problematic. Click here for more details.

@@ -1,5 +1,17 @@
1
1
  import json
2
- from typing import Any, Dict, List, Optional, Tuple, Type, get_type_hints, get_args, get_origin, Union
2
+ from typing import (
3
+ Any,
4
+ Dict,
5
+ List,
6
+ Optional,
7
+ Tuple,
8
+ Type,
9
+ get_type_hints,
10
+ get_args,
11
+ get_origin,
12
+ Union,
13
+ Literal,
14
+ )
3
15
  from pydantic import BaseModel
4
16
  import warnings
5
17
 
@@ -29,13 +41,16 @@ def generate_type_map() -> Dict[Any, str]:
29
41
  # Handle generic Dict type
30
42
  type_map[Dict] = "Dict[Any,Any]"
31
43
  # Provide both key and value types for Dict
32
- type_map[Dict[base_type, base_type]] = f"{collection_name}[{name},{name}]"
44
+ type_map[Dict[base_type, base_type]] = (
45
+ f"{collection_name}[{name},{name}]"
46
+ )
33
47
  # Handle Dict[Any, Any] explicitly
34
48
  type_map[Dict[Any, Any]] = "Dict[Any,Any]"
35
49
  else:
36
50
  type_map[collection[base_type]] = f"{collection_name}[{name}]"
37
51
  return type_map
38
52
 
53
+
39
54
  def generate_example_dict() -> Dict[str, Any]:
40
55
  example_values = {
41
56
  "str": "<Your type-str response here>",
@@ -54,12 +69,13 @@ def generate_example_dict() -> Dict[str, Any]:
54
69
  example_dict[f"Dict[str,{key.split('[')[1]}"] = {value: value}
55
70
  elif key.startswith("Dict"):
56
71
  example_dict[key] = {value: value}
57
-
72
+
58
73
  # Add example for Dict[Any,Any]
59
74
  example_dict["Dict[Any,Any]"] = {"<key>": "<value>"}
60
-
75
+
61
76
  return example_dict
62
77
 
78
+
63
79
  base_type_examples = {
64
80
  int: ("int", 42),
65
81
  float: ("float", 3.14),
@@ -68,13 +84,23 @@ base_type_examples = {
68
84
  Any: ("Any", "<Any value>"),
69
85
  }
70
86
 
87
+
71
88
  def get_type_string(type_hint):
72
89
  origin = get_origin(type_hint)
73
90
  args = get_args(type_hint)
74
91
 
75
92
  if origin is None:
76
93
  if isinstance(type_hint, type) and issubclass(type_hint, BaseModel):
77
- return type_hint.__name__
94
+ # For Pydantic models, create a dictionary of field types
95
+ field_types = {}
96
+ for field_name, field_info in type_hint.model_fields.items():
97
+ field_type = get_type_string(field_info.annotation)
98
+ # Check for Literal type by looking at the origin
99
+ if get_origin(field_info.annotation) is Literal:
100
+ literal_args = get_args(field_info.annotation)
101
+ field_type = f"Literal[{repr(literal_args[0])}]"
102
+ field_types[field_name] = field_type
103
+ return f"{type_hint.__name__}({', '.join(f'{k}: {v}' for k, v in field_types.items())})"
78
104
  else:
79
105
  return base_type_examples.get(type_hint, ("Unknown", "unknown"))[0]
80
106
  elif origin in (list, List):
@@ -89,40 +115,118 @@ def get_type_string(type_hint):
89
115
  if len(non_none_types) == 1:
90
116
  return f"Optional[{get_type_string(non_none_types[0])}]"
91
117
  else:
92
- union_types = ", ".join(get_type_string(t) for t in non_none_types)
93
- return f"Union[{union_types}]"
118
+ # For unions of Pydantic models (like tool calls), show each variant
119
+ union_types = []
120
+ for t in non_none_types:
121
+ if isinstance(t, type) and issubclass(t, BaseModel):
122
+ # Include discriminator field if present
123
+ discriminator = None
124
+ for field_name, field_info in t.model_fields.items():
125
+ if get_origin(field_info.annotation) is Literal:
126
+ literal_args = get_args(field_info.annotation)
127
+ discriminator = f"{field_name}={repr(literal_args[0])}"
128
+ break
129
+ type_str = t.__name__
130
+ if discriminator:
131
+ type_str += f"({discriminator})"
132
+ union_types.append(type_str)
133
+ else:
134
+ union_types.append(get_type_string(t))
135
+ return f"Union[{', '.join(union_types)}]"
136
+ elif origin is Literal:
137
+ # Handle Literal type directly
138
+ return f"Literal[{repr(args[0])}]"
94
139
  else:
95
140
  return "Any"
96
141
 
142
+
97
143
  def get_example_value(type_hint):
98
144
  origin = get_origin(type_hint)
99
145
  args = get_args(type_hint)
100
-
146
+
101
147
  if origin is None:
102
148
  if isinstance(type_hint, type) and issubclass(type_hint, BaseModel):
103
149
  example = {}
150
+ union_docs = []
104
151
  for field_name, field_info in type_hint.model_fields.items():
105
- # Updated attribute from type_ to annotation
106
- example[field_name] = get_example_value(field_info.annotation)
107
- return example
152
+ field_value, field_docs = get_example_value(field_info.annotation)
153
+ if field_docs:
154
+ union_docs.extend(field_docs)
155
+
156
+ # Handle literal fields by checking origin
157
+ if get_origin(field_info.annotation) is Literal:
158
+ literal_args = get_args(field_info.annotation)
159
+ field_value = literal_args[0]
160
+
161
+ # Include field description if available
162
+ if field_info.description:
163
+ example[field_name] = {
164
+ "value": field_value,
165
+ "description": field_info.description,
166
+ }
167
+ else:
168
+ example[field_name] = field_value
169
+ return example, union_docs
108
170
  else:
109
- return base_type_examples.get(type_hint, ("Unknown", "unknown"))[1]
171
+ return base_type_examples.get(type_hint, ("Unknown", "unknown"))[1], []
110
172
  elif origin in (list, List):
111
- return [get_example_value(args[0])]
173
+ value, docs = get_example_value(args[0])
174
+ return [value], docs
112
175
  elif origin in (dict, Dict):
113
176
  if not args or len(args) < 2:
114
177
  warnings.warn(
115
178
  f"Dictionary type hint {type_hint} missing type arguments. "
116
179
  "Defaulting to Dict[str, Any].",
117
- UserWarning
180
+ UserWarning,
118
181
  )
119
- return {"example_key": "<Any value>"} # Default for Dict[str, Any]
120
- return {get_example_value(args[0]): get_example_value(args[1])}
182
+ return {"example_key": "<Any value>"}, [] # Default for Dict[str, Any]
183
+ key_value, key_docs = get_example_value(args[0])
184
+ value_value, value_docs = get_example_value(args[1])
185
+ return {key_value: value_value}, key_docs + value_docs
121
186
  elif origin is Union:
122
187
  non_none_types = [t for t in args if t is not type(None)]
123
- return get_example_value(non_none_types[0])
188
+ # For unions of tool calls, use the first one but preserve the discriminator
189
+ first_type = non_none_types[0]
190
+ union_docs = []
191
+
192
+ if all(
193
+ isinstance(t, type) and issubclass(t, BaseModel) for t in non_none_types
194
+ ):
195
+ # Generate examples for all union variants
196
+ for t in non_none_types:
197
+ example = {}
198
+ for field_name, field_info in t.model_fields.items():
199
+ field_value, _ = get_example_value(field_info.annotation)
200
+ if get_origin(field_info.annotation) is Literal:
201
+ literal_args = get_args(field_info.annotation)
202
+ field_value = literal_args[0]
203
+ example[field_name] = field_value
204
+ union_docs.append(f"\nExample {t.__name__}:")
205
+ union_docs.append(json.dumps(example, indent=2))
206
+
207
+ # Return first type as main example
208
+ if isinstance(first_type, type) and issubclass(first_type, BaseModel):
209
+ example, _ = get_example_value(first_type)
210
+ # Ensure tool_type or other discriminator is preserved
211
+ for field_name, field_info in first_type.model_fields.items():
212
+ if get_origin(field_info.annotation) is Literal:
213
+ literal_args = get_args(field_info.annotation)
214
+ if (
215
+ isinstance(example[field_name], dict)
216
+ and "value" in example[field_name]
217
+ ):
218
+ example[field_name]["value"] = literal_args[0]
219
+ else:
220
+ example[field_name] = literal_args[0]
221
+ return example, union_docs
222
+ main_example, docs = get_example_value(first_type)
223
+ return main_example, docs + union_docs
224
+ elif origin is Literal:
225
+ # Handle Literal type directly
226
+ return args[0], []
124
227
  else:
125
- return "<Unknown>"
228
+ return "<Unknown>", []
229
+
126
230
 
127
231
  def add_json_instructions_to_messages(
128
232
  system_message,
@@ -132,31 +236,53 @@ def add_json_instructions_to_messages(
132
236
  ) -> Tuple[str, str]:
133
237
  if response_model:
134
238
  type_hints = get_type_hints(response_model)
239
+ # print("Type hints", type_hints)
135
240
  stringified_fields = {}
241
+ union_docs = []
136
242
  for key, type_hint in type_hints.items():
137
- example_value = get_example_value(type_hint)
243
+ # print("Key", key, "Type hint", type_hint)
244
+ example_value, docs = get_example_value(type_hint)
245
+ union_docs.extend(docs)
138
246
  field = response_model.model_fields[key] # Updated for Pydantic v2
139
-
247
+
140
248
  # Adjusted for Pydantic v2
141
- field_description = field.description if hasattr(field, 'description') else None
142
-
249
+ field_description = (
250
+ field.description if hasattr(field, "description") else None
251
+ )
252
+
143
253
  if field_description:
144
254
  stringified_fields[key] = (example_value, field_description)
145
255
  else:
146
256
  stringified_fields[key] = example_value
147
257
  example_json = json.dumps(
148
- {k: v[0] if isinstance(v, tuple) else v for k, v in stringified_fields.items()},
149
- indent=4
258
+ {
259
+ k: v[0] if isinstance(v, tuple) else v
260
+ for k, v in stringified_fields.items()
261
+ },
262
+ indent=4,
150
263
  )
151
264
  description_comments = "\n".join(
152
- f'// {k}: {v[1]}' for k, v in stringified_fields.items() if isinstance(v, tuple)
265
+ f"// {k}: {v[1]}"
266
+ for k, v in stringified_fields.items()
267
+ if isinstance(v, tuple)
153
268
  )
269
+
270
+ # print("Example JSON", example_json)
271
+ # print("Description comments", description_comments)
272
+ # print("Union documentation", "\n".join(union_docs))
273
+ # raise Exception("Stop here")
274
+
154
275
  system_message += f"""\n\n
155
276
  Please deliver your response in the following JSON format:
156
277
  ```json
157
278
  {example_json}
158
279
  ```
159
280
  {description_comments}
281
+ """
282
+ if len(union_docs) != 0:
283
+ system_message += f"""\n\n
284
+ NOTE - the above example included a union type. Here are some additional examples for that union type:
285
+ {chr(10).join(union_docs)}
160
286
  """
161
287
  if len(previously_failed_error_messages) != 0:
162
288
  system_message += f"""\n\n
@@ -178,7 +304,10 @@ def inject_structured_output_instructions(
178
304
  prev_system_message_content = messages[0]["content"]
179
305
  prev_user_message_content = messages[1]["content"]
180
306
  system_message, user_message = add_json_instructions_to_messages(
181
- prev_system_message_content, prev_user_message_content, response_model, previously_failed_error_messages
307
+ prev_system_message_content,
308
+ prev_user_message_content,
309
+ response_model,
310
+ previously_failed_error_messages,
182
311
  )
183
312
  messages[0]["content"] = system_message
184
313
  messages[1]["content"] = user_message
@@ -9,11 +9,14 @@ from synth_ai.zyk.lms.caching.initialize import (
9
9
  from synth_ai.zyk.lms.vendors.base import VendorBase
10
10
  from synth_ai.zyk.lms.vendors.constants import SPECIAL_BASE_TEMPS
11
11
  from synth_ai.zyk.lms.vendors.retries import BACKOFF_TOLERANCE, backoff
12
-
12
+ import groq
13
13
  DEFAULT_EXCEPTIONS_TO_RETRY = (
14
14
  pydantic_core._pydantic_core.ValidationError,
15
15
  openai.APIConnectionError,
16
16
  openai.APITimeoutError,
17
+ groq.InternalServerError,
18
+ groq.APITimeoutError,
19
+ groq.APIConnectionError,
17
20
  )
18
21
 
19
22
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: synth-ai
3
- Version: 0.1.0.dev13
3
+ Version: 0.1.0.dev15
4
4
  Summary: Software for aiding the best and multiplying the will.
5
5
  Home-page: https://github.com/synth-laboratories/synth-ai
6
6
  Author: Josh Purtell
@@ -25,12 +25,12 @@ synth_ai/zyk/lms/cost/monitor.py,sha256=cSKIvw6WdPZIRubADWxQoh1MdB40T8-jjgfNUeUH
25
25
  synth_ai/zyk/lms/cost/statefulness.py,sha256=TOsuXL8IjtKOYJ2aJQF8TwJVqn_wQ7AIwJJmdhMye7U,36
26
26
  synth_ai/zyk/lms/structured_outputs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  synth_ai/zyk/lms/structured_outputs/handler.py,sha256=2TixVuVs2w3Q3VB8n2DvNtJcJvUmQzAR1WfXn3FaX7M,13804
28
- synth_ai/zyk/lms/structured_outputs/inject.py,sha256=U3I4-f-9RFn5Pc6wOxqBtJCUOcf_qI5MJGzpxcjhnGI,6732
28
+ synth_ai/zyk/lms/structured_outputs/inject.py,sha256=Fy-zDeleRxOZ8ZRM6IuZ6CP2XZnMe4K2PEn4Q9c_KPY,11777
29
29
  synth_ai/zyk/lms/structured_outputs/rehabilitate.py,sha256=_QOfnI1rJxIE9-zUMhC0PedCOr6y5m6WuGScDb5gcUo,7787
30
30
  synth_ai/zyk/lms/vendors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  synth_ai/zyk/lms/vendors/base.py,sha256=bs27mNfrCjQ5NsmxWnKfxZmpoAa9mTNAFr9AnGVwqLk,552
32
32
  synth_ai/zyk/lms/vendors/constants.py,sha256=zqCOyXZqo297wboR9EKVSkvpq6JCMSJyeso8HdZPKa4,102
33
- synth_ai/zyk/lms/vendors/openai_standard.py,sha256=nTBrI7grru1RjWHluguVU24xt__apXrOnWaq61S71nA,4796
33
+ synth_ai/zyk/lms/vendors/openai_standard.py,sha256=q-gyWs55IzaN91jERD8aPnuxLnG04ErEpNiL-6fqi1s,4892
34
34
  synth_ai/zyk/lms/vendors/retries.py,sha256=m-WvAiPix9ovnO2S-m53Td5VZDWBVBFuHuSK9--OVxw,38
35
35
  synth_ai/zyk/lms/vendors/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  synth_ai/zyk/lms/vendors/core/anthropic_api.py,sha256=fcb0uVlInADl50MNYMT-IimM9mzO19D8_mSg9Gqp92Q,6986
@@ -47,8 +47,8 @@ synth_ai/zyk/lms/vendors/supported/together.py,sha256=Ni_jBqqGPN0PkkY-Ew64s3gNKk
47
47
  tests/test_agent.py,sha256=CjPPWuMWC_TzX1DkDald-bbAxgjXE-HPQvFhq2B--5k,22363
48
48
  tests/test_recursive_structured_outputs.py,sha256=Ne-9XwnOxN7eSpGbNHOpegR-sRj589I84T6y8Z_4QnA,5781
49
49
  tests/test_structured_outputs.py,sha256=J7sfbGZ7OeB5ONIKpcCTymyayNyAdFfGokC1bcUrSx0,3651
50
- synth_ai-0.1.0.dev13.dist-info/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
51
- synth_ai-0.1.0.dev13.dist-info/METADATA,sha256=YKGmgRd5dk-ZgxnWGC8jV7dvc-3rIzHCuc1gKnQSMZM,2773
52
- synth_ai-0.1.0.dev13.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
53
- synth_ai-0.1.0.dev13.dist-info/top_level.txt,sha256=5GzJO9j-KbJ_4ppxhmCUa_qdhHM4-9cHHNU76yAI8do,42
54
- synth_ai-0.1.0.dev13.dist-info/RECORD,,
50
+ synth_ai-0.1.0.dev15.dist-info/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
51
+ synth_ai-0.1.0.dev15.dist-info/METADATA,sha256=4xPOHW4BWRROwbCDJxprZddjA7Xj9957cluvuAF6gFs,2773
52
+ synth_ai-0.1.0.dev15.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
53
+ synth_ai-0.1.0.dev15.dist-info/top_level.txt,sha256=5GzJO9j-KbJ_4ppxhmCUa_qdhHM4-9cHHNU76yAI8do,42
54
+ synth_ai-0.1.0.dev15.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5