synth-ai 0.1.0.dev24__py3-none-any.whl → 0.1.0.dev26__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.
@@ -0,0 +1,106 @@
1
+ import asyncio
2
+ import unittest
3
+
4
+ from synth_ai.zyk import LM
5
+
6
+
7
+ class TestSonnetThinking(unittest.TestCase):
8
+ @classmethod
9
+ def setUpClass(cls):
10
+ cls.lm = LM(
11
+ model_name="claude-3-7-sonnet-latest",
12
+ formatting_model_name="gpt-4o-mini",
13
+ temperature=0,
14
+ )
15
+ # Set reasoning_effort in lm_config
16
+ cls.lm.lm_config["reasoning_effort"] = "high"
17
+
18
+ async def test_thinking_response(self):
19
+ messages = [
20
+ {"role": "system", "content": "You are a helpful AI assistant."},
21
+ {
22
+ "role": "user",
23
+ "content": "Please solve this math problem step by step: If a train travels at 60 mph for 2.5 hours, how far does it travel?",
24
+ },
25
+ ]
26
+
27
+ response = await self.lm.respond_async(messages=messages)
28
+ print("\n=== Math Problem Test ===")
29
+ print(f"Response:\n{response}\n")
30
+ self.assertIsInstance(response, str)
31
+ self.assertGreater(len(response), 0)
32
+
33
+ # Test that the response includes numerical calculation
34
+ self.assertTrue(any(char.isdigit() for char in response))
35
+
36
+ async def test_thinking_structured_output(self):
37
+ from pydantic import BaseModel
38
+
39
+ class MathSolution(BaseModel):
40
+ steps: list[str]
41
+ final_answer: float
42
+ units: str
43
+
44
+ messages = [
45
+ {"role": "system", "content": "You are a math problem solver."},
46
+ {
47
+ "role": "user",
48
+ "content": "If a car travels at 30 mph for 45 minutes, how far does it travel? Provide steps.",
49
+ },
50
+ ]
51
+
52
+ response = await self.lm.respond_async(
53
+ messages=messages, response_model=MathSolution
54
+ )
55
+
56
+ print("\n=== Structured Math Problem Test ===")
57
+ print(f"Steps:")
58
+ for i, step in enumerate(response.steps, 1):
59
+ print(f"{i}. {step}")
60
+ print(f"Final Answer: {response.final_answer} {response.units}\n")
61
+
62
+ self.assertIsInstance(response, MathSolution)
63
+ self.assertGreater(len(response.steps), 0)
64
+ self.assertIsInstance(response.final_answer, float)
65
+ self.assertIsInstance(response.units, str)
66
+
67
+ async def test_thinking_with_high_effort(self):
68
+ messages = [
69
+ {
70
+ "role": "system",
71
+ "content": "You are a problem-solving AI. Break down complex problems into detailed steps.",
72
+ },
73
+ {
74
+ "role": "user",
75
+ "content": "Design a system to automate a coffee shop's inventory management. Consider all aspects.",
76
+ },
77
+ ]
78
+
79
+ print("\n=== High Effort Thinking Test ===")
80
+ response = await self.lm.respond_async(messages=messages)
81
+ print(f"High Effort Response:\n{response}\n")
82
+ self.assertIsInstance(response, str)
83
+ self.assertGreater(len(response), 100) # Expecting detailed response
84
+
85
+ # Test with medium effort
86
+ lm_medium = LM(
87
+ model_name="claude-3-7-sonnet-latest",
88
+ formatting_model_name="gpt-4o-mini",
89
+ temperature=0,
90
+ )
91
+ lm_medium.lm_config["reasoning_effort"] = "medium"
92
+ print("\n=== Medium Effort Thinking Test ===")
93
+ response_medium = await lm_medium.respond_async(messages=messages)
94
+ print(f"Medium Effort Response:\n{response_medium}\n")
95
+ self.assertIsInstance(response_medium, str)
96
+
97
+ def test_all(self):
98
+ print("\nStarting Claude 3.7 Sonnet Thinking Tests...")
99
+ asyncio.run(self.test_thinking_response())
100
+ asyncio.run(self.test_thinking_structured_output())
101
+ asyncio.run(self.test_thinking_with_high_effort())
102
+ print("\nAll tests completed successfully!")
103
+
104
+
105
+ if __name__ == "__main__":
106
+ unittest.main()
@@ -71,7 +71,7 @@ class AnthropicAPI(VendorBase):
71
71
  "system": messages[0]["content"],
72
72
  "messages": messages[1:],
73
73
  "model": model,
74
- "max_tokens": lm_config.get("max_tokens", 4096 * 2), # Default to 16384
74
+ "max_tokens": lm_config.get("max_tokens", 4096 * 2),
75
75
  "temperature": lm_config.get(
76
76
  "temperature", SPECIAL_BASE_TEMPS.get(model, 0)
77
77
  ),
@@ -98,13 +98,24 @@ class AnthropicAPI(VendorBase):
98
98
  api_params["max_tokens"] = max(
99
99
  api_params["max_tokens"], budget + 4096
100
100
  )
101
+ # Set temperature to 1 for thinking, but only in API call
102
+ api_params["temperature"] = 1.0
101
103
  except (ImportError, AttributeError, TypeError):
102
104
  pass
103
105
 
104
106
  # Make the API call
105
107
  response = await self.async_client.messages.create(**api_params)
106
108
 
107
- api_result = response.content[0].text
109
+ # Handle both regular and thinking responses
110
+ if hasattr(response.content[0], "text"):
111
+ api_result = response.content[0].text
112
+ else:
113
+ # For thinking responses, get the final output
114
+ thinking_blocks = [
115
+ block for block in response.content if block.type == "text"
116
+ ]
117
+ api_result = thinking_blocks[-1].value if thinking_blocks else ""
118
+
108
119
  used_cache_handler.add_to_managed_cache(
109
120
  model, messages, lm_config=lm_config, output=api_result
110
121
  )
@@ -177,7 +188,16 @@ class AnthropicAPI(VendorBase):
177
188
  # Make the API call
178
189
  response = self.sync_client.messages.create(**api_params)
179
190
 
180
- api_result = response.content[0].text
191
+ # Handle both regular and thinking responses
192
+ if hasattr(response.content[0], "text"):
193
+ api_result = response.content[0].text
194
+ else:
195
+ # For thinking responses, get the final output
196
+ thinking_blocks = [
197
+ block for block in response.content if block.type == "text"
198
+ ]
199
+ api_result = thinking_blocks[-1].value if thinking_blocks else ""
200
+
181
201
  used_cache_handler.add_to_managed_cache(
182
202
  model, messages, lm_config=lm_config, output=api_result
183
203
  )
@@ -310,21 +330,3 @@ class AnthropicAPI(VendorBase):
310
330
  use_ephemeral_cache_only=use_ephemeral_cache_only,
311
331
  **vendor_params, # Pass all vendor-specific params
312
332
  )
313
-
314
- def _prepare_api_params(self, messages, **kwargs):
315
- # Ensure max_tokens is at least thinking budget + 4096
316
- if "max_tokens" not in kwargs:
317
- kwargs["max_tokens"] = 4096 * 2 # Default to 2x context window
318
-
319
- if "thinking" in kwargs and kwargs.get("thinking", {}).get("budget_tokens"):
320
- thinking_budget = kwargs["thinking"]["budget_tokens"]
321
- kwargs["max_tokens"] = max(kwargs["max_tokens"], thinking_budget + 4096)
322
-
323
- api_params = {
324
- "messages": formatted_messages,
325
- "model": self.model_name,
326
- "max_tokens": kwargs.get("max_tokens", 4096 * 2),
327
- # ... rest of params ...
328
- }
329
-
330
- return api_params
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: synth-ai
3
- Version: 0.1.0.dev24
3
+ Version: 0.1.0.dev26
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
@@ -4,6 +4,7 @@ public_tests/test_all_structured_outputs.py,sha256=x7Gj5Ykpw8Ut_XlSOEBHRLJSagYSH
4
4
  public_tests/test_models.py,sha256=7ZJ2HPDZWhcIeZDDu8Iyt5lOy1xpKpYHM8FzsyEKQmc,5703
5
5
  public_tests/test_reasoning_models.py,sha256=twKNTrWyeTgtqSC2A4V0g79Uq_SjZiBeWp6ntJIAGNM,2779
6
6
  public_tests/test_recursive_structured_outputs.py,sha256=Ne-9XwnOxN7eSpGbNHOpegR-sRj589I84T6y8Z_4QnA,5781
7
+ public_tests/test_sonnet_thinking.py,sha256=SqDKQbjVVhFPBZfS-C0vY_9Hn7Qo-0XEujp0uekU2Ro,3809
7
8
  public_tests/test_structured_outputs.py,sha256=MZitgGedFlvxeaVFzuDQb2xXs8apwvDLTINpGBfsTdM,3653
8
9
  public_tests/test_synth_sdk.py,sha256=jqJHKpvBn9qj21P76z9onXfPg88jyUmBTKmdvCsQMk8,14885
9
10
  synth_ai/__init__.py,sha256=2siivzLbT2r-EA7m91dcJB-6Vsurc5_sX3WiKf4_o8Y,198
@@ -35,7 +36,7 @@ synth_ai/zyk/lms/vendors/constants.py,sha256=zqCOyXZqo297wboR9EKVSkvpq6JCMSJyeso
35
36
  synth_ai/zyk/lms/vendors/openai_standard.py,sha256=TJz1u6IcJ1KHjbofyHs0rlFa13smVXFTtqBSVqEYJqo,5818
36
37
  synth_ai/zyk/lms/vendors/retries.py,sha256=m-WvAiPix9ovnO2S-m53Td5VZDWBVBFuHuSK9--OVxw,38
37
38
  synth_ai/zyk/lms/vendors/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- synth_ai/zyk/lms/vendors/core/anthropic_api.py,sha256=Uge3jg44BNfMNQj9qDybdtSOWzOF9T0kkd1pL0-Do-M,12437
39
+ synth_ai/zyk/lms/vendors/core/anthropic_api.py,sha256=rVAVrjgMXeih3qbISBHf1euilue9Au1n-xDDyQB81n0,12594
39
40
  synth_ai/zyk/lms/vendors/core/gemini_api.py,sha256=Cp8BpSk1yCC3SYrEK1pFOnCdUc65XIPonFEirZ6W2rA,5395
40
41
  synth_ai/zyk/lms/vendors/core/mistral_api.py,sha256=m11ItQ46VyyCUy6hv6mw5OmiqwHr07wV_NJVNnPHgiA,8080
41
42
  synth_ai/zyk/lms/vendors/core/openai_api.py,sha256=700M0QfAxDZXAURnlY--ReEwIEPJPMCwY0JIpu4vptM,5881
@@ -46,11 +47,11 @@ synth_ai/zyk/lms/vendors/supported/deepseek.py,sha256=diFfdhPMO5bLFZxnYj7VT0v6jK
46
47
  synth_ai/zyk/lms/vendors/supported/groq.py,sha256=Fbi7QvhdLx0F-VHO5PY-uIQlPR0bo3C9h1MvIOx8nz0,388
47
48
  synth_ai/zyk/lms/vendors/supported/ollama.py,sha256=K30VBFRTd7NYyPmyBVRZS2sm0UB651AHp9i3wd55W64,469
48
49
  synth_ai/zyk/lms/vendors/supported/together.py,sha256=Ni_jBqqGPN0PkkY-Ew64s3gNKk51k3FCpLSwlNhKbf0,342
49
- synth_ai-0.1.0.dev24.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
50
+ synth_ai-0.1.0.dev26.dist-info/licenses/LICENSE,sha256=ynhjRQUfqA_RdGRATApfFA_fBAy9cno04sLtLUqxVFM,1069
50
51
  tests/test_agent.py,sha256=CjPPWuMWC_TzX1DkDald-bbAxgjXE-HPQvFhq2B--5k,22363
51
52
  tests/test_recursive_structured_outputs.py,sha256=Ne-9XwnOxN7eSpGbNHOpegR-sRj589I84T6y8Z_4QnA,5781
52
53
  tests/test_structured_outputs.py,sha256=J7sfbGZ7OeB5ONIKpcCTymyayNyAdFfGokC1bcUrSx0,3651
53
- synth_ai-0.1.0.dev24.dist-info/METADATA,sha256=JPsOmicj1T8WF0q4XHtRGihSFPe40GmhF1--zg7s0XU,2795
54
- synth_ai-0.1.0.dev24.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
55
- synth_ai-0.1.0.dev24.dist-info/top_level.txt,sha256=5GzJO9j-KbJ_4ppxhmCUa_qdhHM4-9cHHNU76yAI8do,42
56
- synth_ai-0.1.0.dev24.dist-info/RECORD,,
54
+ synth_ai-0.1.0.dev26.dist-info/METADATA,sha256=komo_GbGRf8PbB5uHKqKNCEnHK1cRK9GTvzAEoUFsFM,2795
55
+ synth_ai-0.1.0.dev26.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
56
+ synth_ai-0.1.0.dev26.dist-info/top_level.txt,sha256=5GzJO9j-KbJ_4ppxhmCUa_qdhHM4-9cHHNU76yAI8do,42
57
+ synth_ai-0.1.0.dev26.dist-info/RECORD,,