mito-ai 0.1.33__py3-none-any.whl → 0.1.49__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 (146) hide show
  1. mito_ai/__init__.py +49 -9
  2. mito_ai/_version.py +1 -1
  3. mito_ai/anthropic_client.py +142 -67
  4. mito_ai/{app_builder → app_deploy}/__init__.py +1 -1
  5. mito_ai/app_deploy/app_deploy_utils.py +44 -0
  6. mito_ai/app_deploy/handlers.py +345 -0
  7. mito_ai/{app_builder → app_deploy}/models.py +35 -22
  8. mito_ai/app_manager/__init__.py +4 -0
  9. mito_ai/app_manager/handlers.py +167 -0
  10. mito_ai/app_manager/models.py +71 -0
  11. mito_ai/app_manager/utils.py +24 -0
  12. mito_ai/auth/README.md +18 -0
  13. mito_ai/auth/__init__.py +6 -0
  14. mito_ai/auth/handlers.py +96 -0
  15. mito_ai/auth/urls.py +13 -0
  16. mito_ai/chat_history/handlers.py +63 -0
  17. mito_ai/chat_history/urls.py +32 -0
  18. mito_ai/completions/completion_handlers/agent_execution_handler.py +1 -1
  19. mito_ai/completions/completion_handlers/chat_completion_handler.py +4 -4
  20. mito_ai/completions/completion_handlers/utils.py +99 -37
  21. mito_ai/completions/handlers.py +57 -20
  22. mito_ai/completions/message_history.py +9 -1
  23. mito_ai/completions/models.py +31 -7
  24. mito_ai/completions/prompt_builders/agent_execution_prompt.py +21 -2
  25. mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +8 -0
  26. mito_ai/completions/prompt_builders/agent_system_message.py +115 -42
  27. mito_ai/completions/prompt_builders/chat_name_prompt.py +6 -6
  28. mito_ai/completions/prompt_builders/chat_prompt.py +18 -11
  29. mito_ai/completions/prompt_builders/chat_system_message.py +4 -0
  30. mito_ai/completions/prompt_builders/prompt_constants.py +23 -4
  31. mito_ai/completions/prompt_builders/utils.py +72 -10
  32. mito_ai/completions/providers.py +81 -47
  33. mito_ai/constants.py +25 -24
  34. mito_ai/file_uploads/__init__.py +3 -0
  35. mito_ai/file_uploads/handlers.py +248 -0
  36. mito_ai/file_uploads/urls.py +21 -0
  37. mito_ai/gemini_client.py +44 -48
  38. mito_ai/log/handlers.py +10 -3
  39. mito_ai/log/urls.py +3 -3
  40. mito_ai/openai_client.py +30 -44
  41. mito_ai/path_utils.py +70 -0
  42. mito_ai/streamlit_conversion/agent_utils.py +37 -0
  43. mito_ai/streamlit_conversion/prompts/prompt_constants.py +172 -0
  44. mito_ai/streamlit_conversion/prompts/prompt_utils.py +10 -0
  45. mito_ai/streamlit_conversion/prompts/streamlit_app_creation_prompt.py +46 -0
  46. mito_ai/streamlit_conversion/prompts/streamlit_error_correction_prompt.py +28 -0
  47. mito_ai/streamlit_conversion/prompts/streamlit_finish_todo_prompt.py +45 -0
  48. mito_ai/streamlit_conversion/prompts/streamlit_system_prompt.py +56 -0
  49. mito_ai/streamlit_conversion/prompts/update_existing_app_prompt.py +50 -0
  50. mito_ai/streamlit_conversion/search_replace_utils.py +94 -0
  51. mito_ai/streamlit_conversion/streamlit_agent_handler.py +144 -0
  52. mito_ai/streamlit_conversion/streamlit_utils.py +85 -0
  53. mito_ai/streamlit_conversion/validate_streamlit_app.py +105 -0
  54. mito_ai/streamlit_preview/__init__.py +6 -0
  55. mito_ai/streamlit_preview/handlers.py +111 -0
  56. mito_ai/streamlit_preview/manager.py +152 -0
  57. mito_ai/streamlit_preview/urls.py +22 -0
  58. mito_ai/streamlit_preview/utils.py +29 -0
  59. mito_ai/tests/chat_history/test_chat_history.py +211 -0
  60. mito_ai/tests/completions/completion_handlers_utils_test.py +190 -0
  61. mito_ai/tests/deploy_app/test_app_deploy_utils.py +89 -0
  62. mito_ai/tests/file_uploads/__init__.py +2 -0
  63. mito_ai/tests/file_uploads/test_handlers.py +282 -0
  64. mito_ai/tests/message_history/test_generate_short_chat_name.py +0 -4
  65. mito_ai/tests/message_history/test_message_history_utils.py +103 -23
  66. mito_ai/tests/open_ai_utils_test.py +18 -22
  67. mito_ai/tests/providers/test_anthropic_client.py +447 -0
  68. mito_ai/tests/providers/test_azure.py +2 -6
  69. mito_ai/tests/providers/test_capabilities.py +120 -0
  70. mito_ai/tests/{test_gemini_client.py → providers/test_gemini_client.py} +40 -36
  71. mito_ai/tests/providers/test_mito_server_utils.py +448 -0
  72. mito_ai/tests/providers/test_model_resolution.py +130 -0
  73. mito_ai/tests/providers/test_openai_client.py +57 -0
  74. mito_ai/tests/providers/test_provider_completion_exception.py +66 -0
  75. mito_ai/tests/providers/test_provider_limits.py +42 -0
  76. mito_ai/tests/providers/test_providers.py +382 -0
  77. mito_ai/tests/providers/test_retry_logic.py +389 -0
  78. mito_ai/tests/providers/test_stream_mito_server_utils.py +140 -0
  79. mito_ai/tests/providers/utils.py +85 -0
  80. mito_ai/tests/streamlit_conversion/__init__.py +3 -0
  81. mito_ai/tests/streamlit_conversion/test_apply_search_replace.py +240 -0
  82. mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +246 -0
  83. mito_ai/tests/streamlit_conversion/test_streamlit_utils.py +193 -0
  84. mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +112 -0
  85. mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +118 -0
  86. mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +292 -0
  87. mito_ai/tests/test_constants.py +31 -3
  88. mito_ai/tests/test_telemetry.py +12 -0
  89. mito_ai/tests/user/__init__.py +2 -0
  90. mito_ai/tests/user/test_user.py +120 -0
  91. mito_ai/tests/utils/test_anthropic_utils.py +6 -6
  92. mito_ai/user/handlers.py +45 -0
  93. mito_ai/user/urls.py +21 -0
  94. mito_ai/utils/anthropic_utils.py +55 -121
  95. mito_ai/utils/create.py +17 -1
  96. mito_ai/utils/error_classes.py +42 -0
  97. mito_ai/utils/gemini_utils.py +39 -94
  98. mito_ai/utils/message_history_utils.py +7 -4
  99. mito_ai/utils/mito_server_utils.py +242 -0
  100. mito_ai/utils/open_ai_utils.py +38 -155
  101. mito_ai/utils/provider_utils.py +49 -0
  102. mito_ai/utils/server_limits.py +1 -1
  103. mito_ai/utils/telemetry_utils.py +137 -5
  104. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +102 -100
  105. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/package.json +4 -2
  106. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +3 -1
  107. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +2 -2
  108. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.281f4b9af60d620c6fb1.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js +15948 -8403
  109. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js.map +1 -0
  110. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +198 -0
  111. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +1 -0
  112. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.4f1d00fd0c58fcc05d8d.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.8b24b5b3b93f95205b56.js +58 -33
  113. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.8b24b5b3b93f95205b56.js.map +1 -0
  114. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.06083e515de4862df010.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +10 -2
  115. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +1 -0
  116. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js +533 -0
  117. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js.map +1 -0
  118. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js +6941 -0
  119. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js.map +1 -0
  120. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +1021 -0
  121. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +1 -0
  122. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +59698 -0
  123. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +1 -0
  124. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js +7440 -0
  125. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js.map +1 -0
  126. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.9795f79265ddb416864b.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +2 -240
  127. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +1 -0
  128. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/METADATA +5 -2
  129. mito_ai-0.1.49.dist-info/RECORD +205 -0
  130. mito_ai/app_builder/handlers.py +0 -218
  131. mito_ai/tests/providers_test.py +0 -438
  132. mito_ai/tests/test_anthropic_client.py +0 -270
  133. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.281f4b9af60d620c6fb1.js.map +0 -1
  134. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.4f1d00fd0c58fcc05d8d.js.map +0 -1
  135. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.06083e515de4862df010.js.map +0 -1
  136. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_html2canvas_dist_html2canvas_js.ea47e8c8c906197f8d19.js +0 -7842
  137. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_html2canvas_dist_html2canvas_js.ea47e8c8c906197f8d19.js.map +0 -1
  138. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.9795f79265ddb416864b.js.map +0 -1
  139. mito_ai-0.1.33.dist-info/RECORD +0 -134
  140. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
  141. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
  142. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +0 -0
  143. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +0 -0
  144. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/WHEEL +0 -0
  145. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/entry_points.txt +0 -0
  146. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/licenses/LICENSE +0 -0
@@ -1,270 +0,0 @@
1
- # Copyright (c) Saga Inc.
2
- # Distributed under the terms of the GNU Affero General Public License v3.0 License.
3
-
4
- import pytest
5
- from mito_ai.anthropic_client import get_anthropic_system_prompt_and_messages, extract_and_parse_anthropic_json_response, AnthropicClient, ANTHROPIC_FAST_MODEL
6
- from mito_ai.utils.anthropic_utils import get_anthropic_completion_function_params
7
- from anthropic.types import MessageParam, Message, ContentBlock, TextBlock, ToolUseBlock, Usage
8
- from openai.types.chat import ChatCompletionMessageParam, ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam, ChatCompletionSystemMessageParam
9
- from mito_ai.completions.models import ResponseFormatInfo, AgentResponse
10
- from unittest.mock import MagicMock, patch
11
- import anthropic
12
- from typing import List, Dict, Any, cast, Union
13
-
14
- # Dummy base64 image (1x1 PNG)
15
- DUMMY_IMAGE_DATA_URL = (
16
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wcAAgMBAp9l9AAAAABJRU5ErkJggg=="
17
- )
18
-
19
- def test_mixed_text_and_image():
20
- messages: List[ChatCompletionMessageParam] = [
21
- ChatCompletionSystemMessageParam(role="system", content="You are a helpful assistant."),
22
- ChatCompletionUserMessageParam(role="user", content=[
23
- {"type": "text", "text": "Here is an image:"},
24
- {"type": "image_url", "image_url": {"url": DUMMY_IMAGE_DATA_URL}}
25
- ])
26
- ]
27
- system_prompt, anthropic_messages = get_anthropic_system_prompt_and_messages(messages)
28
-
29
- assert system_prompt == "You are a helpful assistant."
30
- assert len(anthropic_messages) == 1
31
- message = anthropic_messages[0]
32
- assert message["role"] == "user"
33
- content = message["content"]
34
- assert isinstance(content, list)
35
- assert len(content) == 2
36
-
37
- # Check text content
38
- text_block = cast(Dict[str, str], content[0])
39
- assert text_block["type"] == "text"
40
- assert text_block["text"] == "Here is an image:"
41
-
42
- # Check image content
43
- image_block = cast(Dict[str, Dict[str, str]], content[1])
44
- assert image_block["type"] == "image"
45
- assert image_block["source"]["type"] == "base64"
46
- assert image_block["source"]["media_type"] == "image/png"
47
-
48
- def test_no_system_instructions_only_content():
49
- messages: List[ChatCompletionMessageParam] = [
50
- ChatCompletionUserMessageParam(role="user", content="Hello!"),
51
- ChatCompletionAssistantMessageParam(role="assistant", content="Hi, how can I help you?")
52
- ]
53
- system_prompt, anthropic_messages = get_anthropic_system_prompt_and_messages(messages)
54
-
55
- assert isinstance(system_prompt, anthropic.NotGiven)
56
- assert len(anthropic_messages) == 2
57
- assert anthropic_messages[0]["role"] == "user"
58
- assert anthropic_messages[0]["content"] == "Hello!"
59
- assert anthropic_messages[1]["role"] == "assistant"
60
- assert anthropic_messages[1]["content"] == "Hi, how can I help you?"
61
-
62
- def test_system_instructions_and_content():
63
- messages: List[ChatCompletionMessageParam] = [
64
- ChatCompletionSystemMessageParam(role="system", content="You are a helpful assistant."),
65
- ChatCompletionUserMessageParam(role="user", content="What is the weather today?")
66
- ]
67
- system_prompt, anthropic_messages = get_anthropic_system_prompt_and_messages(messages)
68
-
69
- assert system_prompt == "You are a helpful assistant."
70
- assert len(anthropic_messages) == 1
71
- assert anthropic_messages[0]["role"] == "user"
72
- assert anthropic_messages[0]["content"] == "What is the weather today?"
73
-
74
- def test_multiple_system_messages():
75
- messages: List[ChatCompletionMessageParam] = [
76
- ChatCompletionSystemMessageParam(role="system", content="First system message."),
77
- ChatCompletionSystemMessageParam(role="system", content="Second system message."),
78
- ChatCompletionUserMessageParam(role="user", content="Hello!")
79
- ]
80
- system_prompt, anthropic_messages = get_anthropic_system_prompt_and_messages(messages)
81
-
82
- # Should take the last system message
83
- assert system_prompt == "Second system message."
84
- assert len(anthropic_messages) == 1
85
- assert anthropic_messages[0]["role"] == "user"
86
- assert anthropic_messages[0]["content"] == "Hello!"
87
-
88
- def test_empty_message_content():
89
- messages: List[ChatCompletionMessageParam] = [
90
- cast(ChatCompletionMessageParam, {"role": "user"}), # Missing content
91
- ChatCompletionAssistantMessageParam(role="assistant", content="Hi!")
92
- ]
93
- system_prompt, anthropic_messages = get_anthropic_system_prompt_and_messages(messages)
94
-
95
- assert isinstance(system_prompt, anthropic.NotGiven)
96
- assert len(anthropic_messages) == 1 # Should skip the message with missing content
97
- assert anthropic_messages[0]["role"] == "assistant"
98
- assert anthropic_messages[0]["content"] == "Hi!"
99
-
100
- def test_extract_json_from_tool_use():
101
- # Create a mock response with tool use
102
- tool_use_block = ToolUseBlock(
103
- type="tool_use",
104
- id="test_id",
105
- name="agent_response",
106
- input={"key": "value"}
107
- )
108
- response = Message(
109
- id="test_id",
110
- role="assistant",
111
- content=[tool_use_block],
112
- model="claude-3-opus-20240229",
113
- type="message",
114
- usage=Usage(input_tokens=0, output_tokens=0)
115
- )
116
-
117
- result = extract_and_parse_anthropic_json_response(response)
118
- assert result == {"key": "value"}
119
-
120
- def test_extract_json_from_text():
121
- # Create a mock response with JSON in text
122
- text_block = TextBlock(
123
- type="text",
124
- text='Here is some JSON: {"key": "value"}'
125
- )
126
- response = Message(
127
- id="test_id",
128
- role="assistant",
129
- content=[text_block],
130
- model="claude-3-opus-20240229",
131
- type="message",
132
- usage=Usage(input_tokens=0, output_tokens=0)
133
- )
134
-
135
- result = extract_and_parse_anthropic_json_response(response)
136
- assert result == {"key": "value"}
137
-
138
- def test_extract_json_from_text_with_multiple_blocks():
139
- # Create a mock response with multiple text blocks
140
- text_block1 = TextBlock(
141
- type="text",
142
- text='Here is the JSON: {"key": "value"}' # Put JSON in first block since that's what the implementation checks
143
- )
144
- text_block2 = TextBlock(
145
- type="text",
146
- text="Some text after JSON"
147
- )
148
- response = Message(
149
- id="test_id",
150
- role="assistant",
151
- content=[text_block1, text_block2],
152
- model="claude-3-opus-20240229",
153
- type="message",
154
- usage=Usage(input_tokens=0, output_tokens=0)
155
- )
156
-
157
- result = extract_and_parse_anthropic_json_response(response)
158
- assert result == {"key": "value"}
159
-
160
- def test_invalid_json_in_text():
161
- # Create a mock response with invalid JSON in text
162
- text_block = TextBlock(
163
- type="text",
164
- text='Here is invalid JSON: {"key": value}'
165
- )
166
- response = Message(
167
- id="test_id",
168
- role="assistant",
169
- content=[text_block],
170
- model="claude-3-opus-20240229",
171
- type="message",
172
- usage=Usage(input_tokens=0, output_tokens=0)
173
- )
174
-
175
- with pytest.raises(Exception) as exc_info:
176
- extract_and_parse_anthropic_json_response(response)
177
- assert "No valid AgentResponse format found" in str(exc_info.value)
178
-
179
- def test_no_json_in_text():
180
- # Create a mock response with no JSON in text
181
- text_block = TextBlock(
182
- type="text",
183
- text="This is just plain text with no JSON"
184
- )
185
- response = Message(
186
- id="test_id",
187
- role="assistant",
188
- content=[text_block],
189
- model="claude-3-opus-20240229",
190
- type="message",
191
- usage=Usage(input_tokens=0, output_tokens=0)
192
- )
193
-
194
- with pytest.raises(Exception) as exc_info:
195
- extract_and_parse_anthropic_json_response(response)
196
- assert "No valid AgentResponse format found" in str(exc_info.value)
197
-
198
- def test_empty_content():
199
- # Create a mock response with empty content
200
- response = Message(
201
- id="test_id",
202
- role="assistant",
203
- content=[],
204
- model="claude-3-opus-20240229",
205
- type="message",
206
- usage=Usage(input_tokens=0, output_tokens=0)
207
- )
208
-
209
- with pytest.raises(Exception) as exc_info:
210
- extract_and_parse_anthropic_json_response(response)
211
- assert "No valid AgentResponse format found" in str(exc_info.value)
212
-
213
- def test_tool_use_without_agent_response():
214
- # Create a mock response with tool use but not agent_response
215
- tool_use_block = ToolUseBlock(
216
- type="tool_use",
217
- id="test_id",
218
- name="other_tool",
219
- input={"key": "value"}
220
- )
221
- response = Message(
222
- id="test_id",
223
- role="assistant",
224
- content=[tool_use_block],
225
- model="claude-3-opus-20240229",
226
- type="message",
227
- usage=Usage(input_tokens=0, output_tokens=0)
228
- )
229
-
230
- with pytest.raises(Exception) as exc_info:
231
- extract_and_parse_anthropic_json_response(response)
232
- assert "No valid AgentResponse format found" in str(exc_info.value)
233
-
234
- CUSTOM_MODEL = "claude-3-5-sonnet-latest"
235
- @pytest.mark.parametrize("response_format_info, expected_model", [
236
- (ResponseFormatInfo(name="agent_response", format=AgentResponse), CUSTOM_MODEL), # With response_format_info - should use self.model
237
- (None, ANTHROPIC_FAST_MODEL), # Without response_format_info - should use ANTHROPIC_FAST_MODEL
238
- ])
239
- @pytest.mark.asyncio
240
- async def test_model_selection_based_on_response_format_info(response_format_info, expected_model):
241
- """
242
- Tests that the correct model is selected based on whether response_format_info is provided.
243
- """
244
-
245
- # Create an AnthropicClient with a specific model
246
- custom_model = CUSTOM_MODEL
247
- client = AnthropicClient(api_key="test_key", model=custom_model)
248
-
249
- # Mock the messages.create method to avoid actual API calls
250
- client.client = MagicMock()
251
- mock_response = Message(
252
- id="test_id",
253
- role="assistant",
254
- content=[TextBlock(type="text", text="Test response")],
255
- model=custom_model,
256
- type="message",
257
- usage=Usage(input_tokens=0, output_tokens=0)
258
- )
259
- client.client.messages.create.return_value = mock_response
260
-
261
- with patch('mito_ai.anthropic_client.get_anthropic_completion_function_params', wraps=get_anthropic_completion_function_params) as mock_get_params:
262
- await client.request_completions(
263
- messages=[{"role": "user", "content": "Test message"}],
264
- response_format_info=response_format_info
265
- )
266
-
267
- # Verify that get_anthropic_completion_function_params was called with the expected model
268
- mock_get_params.assert_called_once()
269
- call_args = mock_get_params.call_args
270
- assert call_args[1]['model'] == expected_model