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.
- mito_ai/__init__.py +49 -9
- mito_ai/_version.py +1 -1
- mito_ai/anthropic_client.py +142 -67
- mito_ai/{app_builder → app_deploy}/__init__.py +1 -1
- mito_ai/app_deploy/app_deploy_utils.py +44 -0
- mito_ai/app_deploy/handlers.py +345 -0
- mito_ai/{app_builder → app_deploy}/models.py +35 -22
- mito_ai/app_manager/__init__.py +4 -0
- mito_ai/app_manager/handlers.py +167 -0
- mito_ai/app_manager/models.py +71 -0
- mito_ai/app_manager/utils.py +24 -0
- mito_ai/auth/README.md +18 -0
- mito_ai/auth/__init__.py +6 -0
- mito_ai/auth/handlers.py +96 -0
- mito_ai/auth/urls.py +13 -0
- mito_ai/chat_history/handlers.py +63 -0
- mito_ai/chat_history/urls.py +32 -0
- mito_ai/completions/completion_handlers/agent_execution_handler.py +1 -1
- mito_ai/completions/completion_handlers/chat_completion_handler.py +4 -4
- mito_ai/completions/completion_handlers/utils.py +99 -37
- mito_ai/completions/handlers.py +57 -20
- mito_ai/completions/message_history.py +9 -1
- mito_ai/completions/models.py +31 -7
- mito_ai/completions/prompt_builders/agent_execution_prompt.py +21 -2
- mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +8 -0
- mito_ai/completions/prompt_builders/agent_system_message.py +115 -42
- mito_ai/completions/prompt_builders/chat_name_prompt.py +6 -6
- mito_ai/completions/prompt_builders/chat_prompt.py +18 -11
- mito_ai/completions/prompt_builders/chat_system_message.py +4 -0
- mito_ai/completions/prompt_builders/prompt_constants.py +23 -4
- mito_ai/completions/prompt_builders/utils.py +72 -10
- mito_ai/completions/providers.py +81 -47
- mito_ai/constants.py +25 -24
- mito_ai/file_uploads/__init__.py +3 -0
- mito_ai/file_uploads/handlers.py +248 -0
- mito_ai/file_uploads/urls.py +21 -0
- mito_ai/gemini_client.py +44 -48
- mito_ai/log/handlers.py +10 -3
- mito_ai/log/urls.py +3 -3
- mito_ai/openai_client.py +30 -44
- mito_ai/path_utils.py +70 -0
- mito_ai/streamlit_conversion/agent_utils.py +37 -0
- mito_ai/streamlit_conversion/prompts/prompt_constants.py +172 -0
- mito_ai/streamlit_conversion/prompts/prompt_utils.py +10 -0
- mito_ai/streamlit_conversion/prompts/streamlit_app_creation_prompt.py +46 -0
- mito_ai/streamlit_conversion/prompts/streamlit_error_correction_prompt.py +28 -0
- mito_ai/streamlit_conversion/prompts/streamlit_finish_todo_prompt.py +45 -0
- mito_ai/streamlit_conversion/prompts/streamlit_system_prompt.py +56 -0
- mito_ai/streamlit_conversion/prompts/update_existing_app_prompt.py +50 -0
- mito_ai/streamlit_conversion/search_replace_utils.py +94 -0
- mito_ai/streamlit_conversion/streamlit_agent_handler.py +144 -0
- mito_ai/streamlit_conversion/streamlit_utils.py +85 -0
- mito_ai/streamlit_conversion/validate_streamlit_app.py +105 -0
- mito_ai/streamlit_preview/__init__.py +6 -0
- mito_ai/streamlit_preview/handlers.py +111 -0
- mito_ai/streamlit_preview/manager.py +152 -0
- mito_ai/streamlit_preview/urls.py +22 -0
- mito_ai/streamlit_preview/utils.py +29 -0
- mito_ai/tests/chat_history/test_chat_history.py +211 -0
- mito_ai/tests/completions/completion_handlers_utils_test.py +190 -0
- mito_ai/tests/deploy_app/test_app_deploy_utils.py +89 -0
- mito_ai/tests/file_uploads/__init__.py +2 -0
- mito_ai/tests/file_uploads/test_handlers.py +282 -0
- mito_ai/tests/message_history/test_generate_short_chat_name.py +0 -4
- mito_ai/tests/message_history/test_message_history_utils.py +103 -23
- mito_ai/tests/open_ai_utils_test.py +18 -22
- mito_ai/tests/providers/test_anthropic_client.py +447 -0
- mito_ai/tests/providers/test_azure.py +2 -6
- mito_ai/tests/providers/test_capabilities.py +120 -0
- mito_ai/tests/{test_gemini_client.py → providers/test_gemini_client.py} +40 -36
- mito_ai/tests/providers/test_mito_server_utils.py +448 -0
- mito_ai/tests/providers/test_model_resolution.py +130 -0
- mito_ai/tests/providers/test_openai_client.py +57 -0
- mito_ai/tests/providers/test_provider_completion_exception.py +66 -0
- mito_ai/tests/providers/test_provider_limits.py +42 -0
- mito_ai/tests/providers/test_providers.py +382 -0
- mito_ai/tests/providers/test_retry_logic.py +389 -0
- mito_ai/tests/providers/test_stream_mito_server_utils.py +140 -0
- mito_ai/tests/providers/utils.py +85 -0
- mito_ai/tests/streamlit_conversion/__init__.py +3 -0
- mito_ai/tests/streamlit_conversion/test_apply_search_replace.py +240 -0
- mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +246 -0
- mito_ai/tests/streamlit_conversion/test_streamlit_utils.py +193 -0
- mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +112 -0
- mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +118 -0
- mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +292 -0
- mito_ai/tests/test_constants.py +31 -3
- mito_ai/tests/test_telemetry.py +12 -0
- mito_ai/tests/user/__init__.py +2 -0
- mito_ai/tests/user/test_user.py +120 -0
- mito_ai/tests/utils/test_anthropic_utils.py +6 -6
- mito_ai/user/handlers.py +45 -0
- mito_ai/user/urls.py +21 -0
- mito_ai/utils/anthropic_utils.py +55 -121
- mito_ai/utils/create.py +17 -1
- mito_ai/utils/error_classes.py +42 -0
- mito_ai/utils/gemini_utils.py +39 -94
- mito_ai/utils/message_history_utils.py +7 -4
- mito_ai/utils/mito_server_utils.py +242 -0
- mito_ai/utils/open_ai_utils.py +38 -155
- mito_ai/utils/provider_utils.py +49 -0
- mito_ai/utils/server_limits.py +1 -1
- mito_ai/utils/telemetry_utils.py +137 -5
- {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +102 -100
- {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/package.json +4 -2
- {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
- {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
- 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
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js.map +1 -0
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +198 -0
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +1 -0
- 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
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.8b24b5b3b93f95205b56.js.map +1 -0
- 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
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +1 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +1 -0
- {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/METADATA +5 -2
- mito_ai-0.1.49.dist-info/RECORD +205 -0
- mito_ai/app_builder/handlers.py +0 -218
- mito_ai/tests/providers_test.py +0 -438
- mito_ai/tests/test_anthropic_client.py +0 -270
- mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.281f4b9af60d620c6fb1.js.map +0 -1
- mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.4f1d00fd0c58fcc05d8d.js.map +0 -1
- mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.06083e515de4862df010.js.map +0 -1
- mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_html2canvas_dist_html2canvas_js.ea47e8c8c906197f8d19.js +0 -7842
- 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
- mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.9795f79265ddb416864b.js.map +0 -1
- mito_ai-0.1.33.dist-info/RECORD +0 -134
- {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
- {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
- {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
- {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
- {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/WHEEL +0 -0
- {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/entry_points.txt +0 -0
- {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
|