mito-ai 0.1.50__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 +114 -0
- mito_ai/_version.py +4 -0
- mito_ai/anthropic_client.py +334 -0
- mito_ai/app_deploy/__init__.py +6 -0
- mito_ai/app_deploy/app_deploy_utils.py +44 -0
- mito_ai/app_deploy/handlers.py +345 -0
- mito_ai/app_deploy/models.py +98 -0
- 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/__init__.py +3 -0
- mito_ai/completions/completion_handlers/agent_auto_error_fixup_handler.py +59 -0
- mito_ai/completions/completion_handlers/agent_execution_handler.py +66 -0
- mito_ai/completions/completion_handlers/chat_completion_handler.py +141 -0
- mito_ai/completions/completion_handlers/code_explain_handler.py +113 -0
- mito_ai/completions/completion_handlers/completion_handler.py +42 -0
- mito_ai/completions/completion_handlers/inline_completer_handler.py +48 -0
- mito_ai/completions/completion_handlers/smart_debug_handler.py +160 -0
- mito_ai/completions/completion_handlers/utils.py +147 -0
- mito_ai/completions/handlers.py +415 -0
- mito_ai/completions/message_history.py +401 -0
- mito_ai/completions/models.py +404 -0
- mito_ai/completions/prompt_builders/__init__.py +3 -0
- mito_ai/completions/prompt_builders/agent_execution_prompt.py +57 -0
- mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +160 -0
- mito_ai/completions/prompt_builders/agent_system_message.py +472 -0
- mito_ai/completions/prompt_builders/chat_name_prompt.py +15 -0
- mito_ai/completions/prompt_builders/chat_prompt.py +116 -0
- mito_ai/completions/prompt_builders/chat_system_message.py +92 -0
- mito_ai/completions/prompt_builders/explain_code_prompt.py +32 -0
- mito_ai/completions/prompt_builders/inline_completer_prompt.py +197 -0
- mito_ai/completions/prompt_builders/prompt_constants.py +170 -0
- mito_ai/completions/prompt_builders/smart_debug_prompt.py +199 -0
- mito_ai/completions/prompt_builders/utils.py +84 -0
- mito_ai/completions/providers.py +284 -0
- mito_ai/constants.py +63 -0
- mito_ai/db/__init__.py +3 -0
- mito_ai/db/crawlers/__init__.py +6 -0
- mito_ai/db/crawlers/base_crawler.py +61 -0
- mito_ai/db/crawlers/constants.py +43 -0
- mito_ai/db/crawlers/snowflake.py +71 -0
- mito_ai/db/handlers.py +168 -0
- mito_ai/db/models.py +31 -0
- mito_ai/db/urls.py +34 -0
- mito_ai/db/utils.py +185 -0
- mito_ai/docker/mssql/compose.yml +37 -0
- mito_ai/docker/mssql/init/setup.sql +21 -0
- mito_ai/docker/mysql/compose.yml +18 -0
- mito_ai/docker/mysql/init/setup.sql +13 -0
- mito_ai/docker/oracle/compose.yml +17 -0
- mito_ai/docker/oracle/init/setup.sql +20 -0
- mito_ai/docker/postgres/compose.yml +17 -0
- mito_ai/docker/postgres/init/setup.sql +13 -0
- mito_ai/enterprise/__init__.py +3 -0
- mito_ai/enterprise/utils.py +15 -0
- 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 +232 -0
- mito_ai/log/handlers.py +38 -0
- mito_ai/log/urls.py +21 -0
- mito_ai/logger.py +37 -0
- mito_ai/openai_client.py +382 -0
- mito_ai/path_utils.py +70 -0
- mito_ai/rules/handlers.py +44 -0
- mito_ai/rules/urls.py +22 -0
- mito_ai/rules/utils.py +56 -0
- mito_ai/settings/handlers.py +41 -0
- mito_ai/settings/urls.py +20 -0
- mito_ai/settings/utils.py +42 -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/__init__.py +3 -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/conftest.py +53 -0
- mito_ai/tests/create_agent_system_message_prompt_test.py +22 -0
- mito_ai/tests/data/prompt_lg.py +69 -0
- mito_ai/tests/data/prompt_sm.py +6 -0
- mito_ai/tests/data/prompt_xl.py +13 -0
- mito_ai/tests/data/stock_data.sqlite3 +0 -0
- mito_ai/tests/db/conftest.py +39 -0
- mito_ai/tests/db/connections_test.py +102 -0
- mito_ai/tests/db/mssql_test.py +29 -0
- mito_ai/tests/db/mysql_test.py +29 -0
- mito_ai/tests/db/oracle_test.py +29 -0
- mito_ai/tests/db/postgres_test.py +29 -0
- mito_ai/tests/db/schema_test.py +93 -0
- mito_ai/tests/db/sqlite_test.py +31 -0
- mito_ai/tests/db/test_db_constants.py +61 -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 +120 -0
- mito_ai/tests/message_history/test_message_history_utils.py +469 -0
- mito_ai/tests/open_ai_utils_test.py +152 -0
- mito_ai/tests/performance_test.py +329 -0
- mito_ai/tests/providers/test_anthropic_client.py +447 -0
- mito_ai/tests/providers/test_azure.py +631 -0
- mito_ai/tests/providers/test_capabilities.py +120 -0
- mito_ai/tests/providers/test_gemini_client.py +195 -0
- 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/rules/conftest.py +26 -0
- mito_ai/tests/rules/rules_test.py +117 -0
- mito_ai/tests/server_limits_test.py +406 -0
- mito_ai/tests/settings/conftest.py +26 -0
- mito_ai/tests/settings/settings_test.py +70 -0
- mito_ai/tests/settings/test_settings_constants.py +9 -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 +47 -0
- 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/__init__.py +3 -0
- mito_ai/tests/utils/test_anthropic_utils.py +162 -0
- mito_ai/tests/utils/test_gemini_utils.py +98 -0
- mito_ai/tests/version_check_test.py +169 -0
- mito_ai/user/handlers.py +45 -0
- mito_ai/user/urls.py +21 -0
- mito_ai/utils/__init__.py +3 -0
- mito_ai/utils/anthropic_utils.py +168 -0
- mito_ai/utils/create.py +94 -0
- mito_ai/utils/db.py +74 -0
- mito_ai/utils/error_classes.py +42 -0
- mito_ai/utils/gemini_utils.py +133 -0
- mito_ai/utils/message_history_utils.py +87 -0
- mito_ai/utils/mito_server_utils.py +242 -0
- mito_ai/utils/open_ai_utils.py +200 -0
- mito_ai/utils/provider_utils.py +49 -0
- mito_ai/utils/schema.py +86 -0
- mito_ai/utils/server_limits.py +152 -0
- mito_ai/utils/telemetry_utils.py +480 -0
- mito_ai/utils/utils.py +89 -0
- mito_ai/utils/version_utils.py +94 -0
- mito_ai/utils/websocket_base.py +88 -0
- mito_ai/version_check.py +60 -0
- mito_ai-0.1.50.data/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +7 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/build_log.json +728 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/package.json +243 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +238 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +37 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js +21602 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +198 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.78d3ccb73e7ca1da3aae.js +619 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.78d3ccb73e7ca1da3aae.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style.js +4 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +712 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +1 -0
- mito_ai-0.1.50.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.50.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.50.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.50.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.50.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.50.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.50.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.50.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.50.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.50.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.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +2792 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +1 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +4859 -0
- mito_ai-0.1.50.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +1 -0
- mito_ai-0.1.50.dist-info/METADATA +221 -0
- mito_ai-0.1.50.dist-info/RECORD +205 -0
- mito_ai-0.1.50.dist-info/WHEEL +4 -0
- mito_ai-0.1.50.dist-info/entry_points.txt +2 -0
- mito_ai-0.1.50.dist-info/licenses/LICENSE +3 -0
mito_ai/utils/utils.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import pkg_resources
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
import uuid
|
|
9
|
+
from typing import List, Optional, Tuple, Union
|
|
10
|
+
from tornado.httpclient import AsyncHTTPClient
|
|
11
|
+
|
|
12
|
+
def get_random_id() -> str:
|
|
13
|
+
"""
|
|
14
|
+
Creates a new random ID for the user, which for any given user,
|
|
15
|
+
should only happen once.
|
|
16
|
+
"""
|
|
17
|
+
return str(uuid.uuid1())
|
|
18
|
+
|
|
19
|
+
def is_running_test() -> bool:
|
|
20
|
+
"""
|
|
21
|
+
A helper function that quickly returns if the current code is running
|
|
22
|
+
inside of a test, which is useful for making sure we don't generate
|
|
23
|
+
tons of logs.
|
|
24
|
+
"""
|
|
25
|
+
# Pytest injects PYTEST_CURRENT_TEST into the current environment when running
|
|
26
|
+
running_pytests = "PYTEST_CURRENT_TEST" in os.environ
|
|
27
|
+
|
|
28
|
+
# Github injects CI into the environment when running
|
|
29
|
+
running_ci = 'CI' in os.environ and os.environ['CI'] is not None
|
|
30
|
+
|
|
31
|
+
return running_pytests or running_ci
|
|
32
|
+
|
|
33
|
+
def get_installed_packages() -> List[str]:
|
|
34
|
+
"""
|
|
35
|
+
Get a list of all installed packages.
|
|
36
|
+
"""
|
|
37
|
+
return [
|
|
38
|
+
package.key
|
|
39
|
+
for package in sorted(pkg_resources.working_set, key=lambda x: x.key)
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
def install_packages(packages: List[str]) -> dict[str, Union[bool, str, None]]:
|
|
43
|
+
"""
|
|
44
|
+
Install a list of packages.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
dict: A dictionary containing:
|
|
48
|
+
- 'success': bool
|
|
49
|
+
- 'error': error message captured from the subprocess call or None if no error
|
|
50
|
+
"""
|
|
51
|
+
result: dict[str, Union[bool, str, None]] = {
|
|
52
|
+
'success': True,
|
|
53
|
+
'error': None
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
for package in packages:
|
|
57
|
+
try:
|
|
58
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
|
59
|
+
except subprocess.CalledProcessError as e:
|
|
60
|
+
result['success'] = False
|
|
61
|
+
result['error'] = str(e)
|
|
62
|
+
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
def _create_http_client(timeout: int, max_retries: int) -> Tuple[AsyncHTTPClient, Optional[int]]:
|
|
66
|
+
"""
|
|
67
|
+
Create an HTTP client with appropriate timeout settings.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
timeout: The timeout in seconds
|
|
71
|
+
max_retries: The maximum number of retries
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
A tuple containing the HTTP client and the timeout value in milliseconds
|
|
75
|
+
"""
|
|
76
|
+
from .utils import is_running_test # local import to avoid circular import if needed
|
|
77
|
+
if is_running_test():
|
|
78
|
+
# If we are running in a test environment, setting the request_timeout fails for some reason.
|
|
79
|
+
http_client = AsyncHTTPClient(defaults=dict(user_agent="Mito-AI client"))
|
|
80
|
+
http_client_timeout = None
|
|
81
|
+
else:
|
|
82
|
+
# To avoid 599 client timeout errors, we set the request_timeout. By default, the HTTP client
|
|
83
|
+
# timesout after 20 seconds. We update this to match the timeout we give to OpenAI.
|
|
84
|
+
# The OpenAI timeouts are denoted in seconds, whereas the HTTP client expects milliseconds.
|
|
85
|
+
# We also give the HTTP client a 10 second buffer to account for
|
|
86
|
+
http_client_timeout = timeout * 1000 * max_retries + 10000
|
|
87
|
+
http_client = AsyncHTTPClient(defaults=dict(user_agent="Mito-AI client", request_timeout=http_client_timeout))
|
|
88
|
+
|
|
89
|
+
return http_client, http_client_timeout
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from typing import cast
|
|
6
|
+
from .schema import UJ_MITOSHEET_ENTERPRISE, UJ_MITOSHEET_PRO
|
|
7
|
+
from .db import get_user_field
|
|
8
|
+
|
|
9
|
+
# Check if helper packages are installed
|
|
10
|
+
try:
|
|
11
|
+
import mitosheet_helper_pro
|
|
12
|
+
MITOSHEET_HELPER_PRO = True
|
|
13
|
+
except ImportError:
|
|
14
|
+
MITOSHEET_HELPER_PRO = False
|
|
15
|
+
try:
|
|
16
|
+
import mitosheet_helper_enterprise
|
|
17
|
+
MITOSHEET_HELPER_ENTERPRISE = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
MITOSHEET_HELPER_ENTERPRISE = False
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
import mitosheet_private
|
|
23
|
+
MITOSHEET_PRIVATE = True
|
|
24
|
+
except ImportError:
|
|
25
|
+
MITOSHEET_PRIVATE = False
|
|
26
|
+
|
|
27
|
+
# This is a legacy helper that we don't use anymore, however, we're keeping it for now
|
|
28
|
+
# for backwards compatibility, since I'm not 100% confident that nobody is currently using it.
|
|
29
|
+
try:
|
|
30
|
+
import mitosheet_helper_private
|
|
31
|
+
MITOSHEET_HELPER_PRIVATE = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
MITOSHEET_HELPER_PRIVATE = False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def is_pro() -> bool:
|
|
37
|
+
"""
|
|
38
|
+
Helper function for returning if this is a
|
|
39
|
+
pro deployment of mito
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# This package overides the user.json
|
|
43
|
+
if MITOSHEET_HELPER_PRO:
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
# This package overides the user.json
|
|
47
|
+
if MITOSHEET_PRIVATE:
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
# Check if the config is set
|
|
51
|
+
# TODO: Check if the mito config pro is set to true.
|
|
52
|
+
# I don't think that any user is on pro via this method
|
|
53
|
+
|
|
54
|
+
# If you're on Mito Enterprise, then you get all Mito Pro features
|
|
55
|
+
if is_enterprise():
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
pro = get_user_field(UJ_MITOSHEET_PRO)
|
|
59
|
+
if pro is None:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
return bool(pro)
|
|
63
|
+
|
|
64
|
+
def is_enterprise() -> bool:
|
|
65
|
+
"""
|
|
66
|
+
Helper function for returning if this is a Mito Enterprise
|
|
67
|
+
users
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
# This package overides the user.json
|
|
71
|
+
if MITOSHEET_HELPER_ENTERPRISE:
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
# TODO: Check if the mito config enterprise is set to true.
|
|
75
|
+
# I don't think that any user is on enterprise via this method
|
|
76
|
+
|
|
77
|
+
is_enterprise = get_user_field(UJ_MITOSHEET_ENTERPRISE)
|
|
78
|
+
if is_enterprise is None:
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
# TODO: Check if someone has a temp enterprise license set
|
|
82
|
+
|
|
83
|
+
return bool(is_enterprise)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def is_mitosheet_private() -> bool:
|
|
87
|
+
"""
|
|
88
|
+
Helper function for returning if this is a Mito Private
|
|
89
|
+
users
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
if MITOSHEET_PRIVATE:
|
|
93
|
+
return True
|
|
94
|
+
return False
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
from dataclasses import asdict
|
|
7
|
+
from http import HTTPStatus
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
import tornado
|
|
11
|
+
from jupyter_core.utils import ensure_async
|
|
12
|
+
from jupyter_server.base.handlers import JupyterHandler
|
|
13
|
+
from tornado.websocket import WebSocketHandler
|
|
14
|
+
|
|
15
|
+
from mito_ai.logger import get_logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseWebSocketHandler(JupyterHandler, WebSocketHandler):
|
|
19
|
+
"""Base WebSocket handler with common functionality for Mito AI services."""
|
|
20
|
+
|
|
21
|
+
def initialize(self) -> None:
|
|
22
|
+
"""Initialize the WebSocket handler."""
|
|
23
|
+
super().initialize()
|
|
24
|
+
self.log.debug("Initializing websocket connection %s", self.request.path)
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def log(self) -> logging.Logger:
|
|
28
|
+
"""Use Mito AI logger."""
|
|
29
|
+
return get_logger()
|
|
30
|
+
|
|
31
|
+
async def pre_get(self) -> None:
|
|
32
|
+
"""Handle WebSocket authentication/authorization."""
|
|
33
|
+
# Authenticate the request before opening the WebSocket
|
|
34
|
+
user = self.current_user
|
|
35
|
+
if user is None:
|
|
36
|
+
self.log.warning("Couldn't authenticate WebSocket connection")
|
|
37
|
+
raise tornado.web.HTTPError(HTTPStatus.UNAUTHORIZED)
|
|
38
|
+
|
|
39
|
+
# Authorize the user
|
|
40
|
+
if not await ensure_async(
|
|
41
|
+
self.authorizer.is_authorized(self, user, "execute", "mito-ai")
|
|
42
|
+
):
|
|
43
|
+
raise tornado.web.HTTPError(HTTPStatus.FORBIDDEN)
|
|
44
|
+
|
|
45
|
+
async def get(self, *args: Any, **kwargs: Dict[str, Any]) -> None:
|
|
46
|
+
"""Get an event to open a socket or check service availability."""
|
|
47
|
+
# Check if this is just a service availability check
|
|
48
|
+
if self.get_query_argument('check_availability', None) == 'true':
|
|
49
|
+
self.set_status(HTTPStatus.OK)
|
|
50
|
+
self.finish()
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
await ensure_async(self.pre_get()) # type: ignore
|
|
54
|
+
|
|
55
|
+
reply = super().get(*args, **kwargs)
|
|
56
|
+
if reply is not None:
|
|
57
|
+
await reply
|
|
58
|
+
|
|
59
|
+
def reply(self, reply: Any) -> None:
|
|
60
|
+
"""Write a reply object to the WebSocket connection.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
reply: The reply object, which must be a dataclass instance.
|
|
64
|
+
"""
|
|
65
|
+
message = asdict(reply)
|
|
66
|
+
super().write_message(message)
|
|
67
|
+
|
|
68
|
+
def on_close(self) -> None:
|
|
69
|
+
"""Invoked when the WebSocket is closed."""
|
|
70
|
+
self.log.debug("WebSocket closed: %s", self.request.path)
|
|
71
|
+
|
|
72
|
+
def parse_message(self, message: str) -> Dict[str, Any]:
|
|
73
|
+
"""Parse an incoming message.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
message: The JSON message string to parse.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
The parsed message as a dict.
|
|
80
|
+
|
|
81
|
+
Raises:
|
|
82
|
+
ValueError: If the message is not valid JSON.
|
|
83
|
+
"""
|
|
84
|
+
try:
|
|
85
|
+
return json.loads(message) # type: ignore
|
|
86
|
+
except ValueError as e:
|
|
87
|
+
self.log.error("Invalid message: %s", e)
|
|
88
|
+
raise
|
mito_ai/version_check.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Version check endpoint for Mito AI to compare local and PyPI versions.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import logging
|
|
9
|
+
import time
|
|
10
|
+
from functools import lru_cache
|
|
11
|
+
from typing import Tuple, Optional, Any
|
|
12
|
+
import requests
|
|
13
|
+
import tornado.web
|
|
14
|
+
from tornado.web import RequestHandler
|
|
15
|
+
from mito_ai._version import __version__
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
class VersionCheckHandler(RequestHandler):
|
|
20
|
+
"""Handler for checking the latest version of Mito AI on PyPI."""
|
|
21
|
+
|
|
22
|
+
# Cache PyPI results for 1 hour (3600 seconds)
|
|
23
|
+
@staticmethod
|
|
24
|
+
@lru_cache(maxsize=1)
|
|
25
|
+
def _get_latest_version() -> Tuple[Optional[str], float]:
|
|
26
|
+
"""Get the latest version from PyPI with caching."""
|
|
27
|
+
cache_time = time.time()
|
|
28
|
+
try:
|
|
29
|
+
response = requests.get("https://pypi.org/pypi/mito-ai/json", timeout=3)
|
|
30
|
+
response.raise_for_status()
|
|
31
|
+
pypi_data = response.json()
|
|
32
|
+
latest_version = pypi_data.get("info", {}).get("version", "")
|
|
33
|
+
return latest_version, cache_time
|
|
34
|
+
except (requests.RequestException, json.JSONDecodeError) as e:
|
|
35
|
+
logger.warning(f"Failed to fetch latest version from PyPI: {str(e)}")
|
|
36
|
+
return None, cache_time
|
|
37
|
+
|
|
38
|
+
def get(self) -> None:
|
|
39
|
+
"""Get the current and latest Mito AI versions."""
|
|
40
|
+
try:
|
|
41
|
+
# Get current package version from _version.py
|
|
42
|
+
current_version = __version__
|
|
43
|
+
|
|
44
|
+
# Get latest version from PyPI with caching
|
|
45
|
+
latest_version, cache_time = self._get_latest_version()
|
|
46
|
+
cache_age = time.time() - cache_time
|
|
47
|
+
|
|
48
|
+
# Include cache information in response
|
|
49
|
+
self.set_header("Content-Type", "application/json")
|
|
50
|
+
self.write(json.dumps({
|
|
51
|
+
"current_version": current_version,
|
|
52
|
+
"latest_version": latest_version,
|
|
53
|
+
"cache_age_seconds": int(cache_age)
|
|
54
|
+
}))
|
|
55
|
+
except Exception as e:
|
|
56
|
+
logger.error(f"Error in version check: {str(e)}")
|
|
57
|
+
self.set_status(500)
|
|
58
|
+
self.write(json.dumps({
|
|
59
|
+
"error": "Failed to check versions"
|
|
60
|
+
}))
|