mito-ai 0.1.43__py3-none-any.whl → 0.1.45__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 mito-ai might be problematic. Click here for more details.

Files changed (62) hide show
  1. mito_ai/__init__.py +3 -3
  2. mito_ai/_version.py +1 -1
  3. mito_ai/anthropic_client.py +2 -3
  4. mito_ai/{app_builder → app_deploy}/__init__.py +1 -1
  5. mito_ai/app_deploy/app_deploy_utils.py +25 -0
  6. mito_ai/{app_builder → app_deploy}/handlers.py +48 -40
  7. mito_ai/{app_builder → app_deploy}/models.py +17 -14
  8. mito_ai/app_manager/handlers.py +33 -0
  9. mito_ai/app_manager/models.py +15 -1
  10. mito_ai/completions/handlers.py +40 -1
  11. mito_ai/completions/models.py +5 -1
  12. mito_ai/completions/prompt_builders/agent_system_message.py +6 -4
  13. mito_ai/completions/prompt_builders/prompt_constants.py +22 -4
  14. mito_ai/completions/providers.py +5 -11
  15. mito_ai/streamlit_conversion/streamlit_agent_handler.py +6 -3
  16. mito_ai/streamlit_conversion/streamlit_utils.py +15 -7
  17. mito_ai/streamlit_conversion/validate_streamlit_app.py +34 -25
  18. mito_ai/streamlit_preview/handlers.py +49 -70
  19. mito_ai/streamlit_preview/utils.py +41 -0
  20. mito_ai/tests/deploy_app/test_app_deploy_utils.py +71 -0
  21. mito_ai/tests/providers/test_anthropic_client.py +2 -2
  22. mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +0 -84
  23. mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +0 -15
  24. mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +88 -0
  25. mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +4 -1
  26. mito_ai/tests/utils/test_anthropic_utils.py +4 -4
  27. mito_ai/utils/anthropic_utils.py +11 -19
  28. mito_ai/utils/telemetry_utils.py +15 -5
  29. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +100 -100
  30. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/package.json +2 -2
  31. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +1 -1
  32. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +0 -5
  33. mito_ai-0.1.43.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.81703ac2bc645e5c2fc2.js → mito_ai-0.1.45.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.0c3368195d954d2ed033.js +1729 -790
  34. mito_ai-0.1.45.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.0c3368195d954d2ed033.js.map +1 -0
  35. mito_ai-0.1.43.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.502aef26f0416fab7435.js → mito_ai-0.1.45.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.684f82575fcc2e3b350c.js +17 -17
  36. mito_ai-0.1.43.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.502aef26f0416fab7435.js.map → mito_ai-0.1.45.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.684f82575fcc2e3b350c.js.map +1 -1
  37. {mito_ai-0.1.43.dist-info → mito_ai-0.1.45.dist-info}/METADATA +2 -2
  38. {mito_ai-0.1.43.dist-info → mito_ai-0.1.45.dist-info}/RECORD +61 -57
  39. mito_ai-0.1.43.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.81703ac2bc645e5c2fc2.js.map +0 -1
  40. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
  41. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +0 -0
  42. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +0 -0
  43. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
  44. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +0 -0
  45. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +0 -0
  46. {mito_ai-0.1.43.data → mito_ai-0.1.45.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 +0 -0
  47. {mito_ai-0.1.43.data → mito_ai-0.1.45.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 +0 -0
  48. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js +0 -0
  49. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js.map +0 -0
  50. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +0 -0
  51. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +0 -0
  52. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +0 -0
  53. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +0 -0
  54. {mito_ai-0.1.43.data → mito_ai-0.1.45.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 +0 -0
  55. {mito_ai-0.1.43.data → mito_ai-0.1.45.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 +0 -0
  56. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +0 -0
  57. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +0 -0
  58. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +0 -0
  59. {mito_ai-0.1.43.data → mito_ai-0.1.45.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +0 -0
  60. {mito_ai-0.1.43.dist-info → mito_ai-0.1.45.dist-info}/WHEEL +0 -0
  61. {mito_ai-0.1.43.dist-info → mito_ai-0.1.45.dist-info}/entry_points.txt +0 -0
  62. {mito_ai-0.1.43.dist-info → mito_ai-0.1.45.dist-info}/licenses/LICENSE +0 -0
@@ -87,21 +87,6 @@ df=pd.read_csv('data.csv')
87
87
  validator = StreamlitValidator()
88
88
  errors = validator.get_runtime_errors(app_code, app_path)
89
89
  assert errors is None
90
-
91
-
92
- @patch('subprocess.Popen')
93
- def test_cleanup_with_process(self, mock_popen):
94
- """Test cleanup with running process"""
95
- validator = StreamlitValidator()
96
- validator.temp_dir = "/tmp/test_dir"
97
-
98
- # Mock directory exists
99
- with patch('os.path.exists', return_value=True):
100
- with patch('shutil.rmtree') as mock_rmtree:
101
- validator.cleanup()
102
-
103
- mock_rmtree.assert_called_once()
104
-
105
90
 
106
91
  @pytest.mark.parametrize("app_code,expected_has_validation_error,expected_error_message", [
107
92
  ("x=5", 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 pytest
5
+ import os
6
+ import tempfile
7
+ from unittest.mock import patch, AsyncMock, MagicMock
8
+ from mito_ai.streamlit_preview.utils import ensure_app_exists
9
+
10
+
11
+ class TestEnsureAppExists:
12
+ """Test cases for the ensure_app_exists function."""
13
+
14
+ @pytest.mark.asyncio
15
+ @pytest.mark.parametrize(
16
+ "app_exists,streamlit_handler_success,expected_success,expected_error,streamlit_handler_called,streamlit_handler_return",
17
+ [
18
+ # Test case 1: App exists, should use existing file
19
+ (
20
+ True, # app_exists
21
+ True, # streamlit_handler_success (not relevant)
22
+ True, # expected_success
23
+ "", # expected_error
24
+ False, # streamlit_handler_called
25
+ None, # streamlit_handler_return (not used)
26
+ ),
27
+ # Test case 2: App doesn't exist, streamlit_handler succeeds
28
+ (
29
+ False, # app_exists
30
+ True, # streamlit_handler_success
31
+ True, # expected_success
32
+ "", # expected_error
33
+ True, # streamlit_handler_called
34
+ (True, "/path/to/app.py", "Success"), # streamlit_handler_return
35
+ )
36
+ ],
37
+ ids=[
38
+ "app_exists_uses_existing_file",
39
+ "app_does_not_exist_generates_new_one_success",
40
+ ]
41
+ )
42
+ async def test_ensure_app_exists(
43
+ self,
44
+ app_exists,
45
+ streamlit_handler_success,
46
+ expected_success,
47
+ expected_error,
48
+ streamlit_handler_called,
49
+ streamlit_handler_return,
50
+ ):
51
+ """Test ensure_app_exists function with various scenarios."""
52
+ with tempfile.TemporaryDirectory() as temp_dir:
53
+ notebook_path = os.path.join(temp_dir, "test_notebook.ipynb")
54
+
55
+ # Set up app_path based on whether app exists
56
+ app_path = os.path.join(temp_dir, "app.py") if app_exists else None
57
+
58
+ # Create app.py file if it should exist
59
+ if app_exists:
60
+ assert app_path is not None # Type assertion for mypy
61
+ with open(app_path, "w") as f:
62
+ f.write("import streamlit as st\nst.write('Hello World')")
63
+
64
+ # Mock get_app_path to return the appropriate value
65
+ with patch('mito_ai.streamlit_preview.utils.get_app_path') as mock_get_app_path:
66
+ mock_get_app_path.return_value = app_path
67
+
68
+ # Mock streamlit_handler
69
+ with patch('mito_ai.streamlit_preview.utils.streamlit_handler') as mock_streamlit_handler:
70
+ if streamlit_handler_return is not None:
71
+ mock_streamlit_handler.return_value = streamlit_handler_return
72
+
73
+ success, error_msg = await ensure_app_exists(notebook_path)
74
+
75
+ # Assertions
76
+ assert success == expected_success
77
+ assert error_msg == expected_error
78
+
79
+ # Verify get_app_path was called with the correct directory
80
+ mock_get_app_path.assert_called_once_with(temp_dir)
81
+
82
+ # Verify streamlit_handler was called or not called as expected
83
+ if streamlit_handler_called:
84
+ mock_streamlit_handler.assert_called_once_with(notebook_path)
85
+ else:
86
+ mock_streamlit_handler.assert_not_called()
87
+
88
+
@@ -9,6 +9,7 @@ import shutil
9
9
  import subprocess
10
10
  import threading
11
11
  import requests
12
+ import json
12
13
  from unittest.mock import Mock, patch, MagicMock
13
14
  from typing import Any
14
15
 
@@ -17,6 +18,8 @@ from mito_ai.streamlit_preview.manager import (
17
18
  PreviewProcess,
18
19
  get_preview_manager
19
20
  )
21
+ from mito_ai.streamlit_preview.handlers import StreamlitPreviewHandler
22
+ from mito_ai.streamlit_conversion.streamlit_utils import get_app_path
20
23
 
21
24
 
22
25
  class TestStreamlitPreviewManager:
@@ -299,4 +302,4 @@ st.write("Hello, World!")
299
302
  # Verify they're gone
300
303
  for preview_id in preview_ids:
301
304
  assert manager.get_preview(preview_id) is None
302
-
305
+
@@ -35,7 +35,7 @@ def test_basic_request_preparation():
35
35
  max_tokens = 100
36
36
  temperature = 0.7
37
37
  # Use NotGiven to ensure system is not included in inner_data
38
- system = anthropic.NotGiven()
38
+ system = anthropic.Omit()
39
39
  messages: List[MessageParam] = [{"role": "user", "content": "Hello"}]
40
40
  message_type = MessageType.CHAT
41
41
 
@@ -106,7 +106,7 @@ def test_tools_and_tool_choice():
106
106
  model="claude-3-sonnet",
107
107
  max_tokens=100,
108
108
  temperature=0.7,
109
- system=anthropic.NotGiven(),
109
+ system=anthropic.Omit(),
110
110
  messages=[{"role": "user", "content": "Hello"}],
111
111
  message_type=MessageType.CHAT,
112
112
  tools=tools,
@@ -124,7 +124,7 @@ def test_stream_parameter():
124
124
  model="claude-3-sonnet",
125
125
  max_tokens=100,
126
126
  temperature=0.7,
127
- system=anthropic.NotGiven(),
127
+ system=anthropic.Omit(),
128
128
  messages=[{"role": "user", "content": "Hello"}],
129
129
  message_type=MessageType.CHAT,
130
130
  tools=None,
@@ -150,7 +150,7 @@ def test_missing_user_info(monkeypatch):
150
150
  model="claude-3-sonnet",
151
151
  max_tokens=100,
152
152
  temperature=0.7,
153
- system=anthropic.NotGiven(),
153
+ system=anthropic.Omit(),
154
154
  messages=[{"role": "user", "content": "Hello"}],
155
155
  message_type=MessageType.CHAT,
156
156
  tools=None,
@@ -1,23 +1,14 @@
1
1
  # Copyright (c) Saga Inc.
2
2
  # Distributed under the terms of the GNU Affero General Public License v3.0 License.
3
3
 
4
- import asyncio
5
- import json
6
- import time
7
4
  import anthropic
8
- from typing import Any, Dict, List, Optional, Union, AsyncGenerator, Tuple, Callable, cast
9
-
10
- from anthropic.types import MessageParam, Message, TextBlock, ToolUnionParam
5
+ from typing import Any, Dict, List, Optional, Union, AsyncGenerator, Tuple, Callable
6
+ from anthropic.types import MessageParam, ToolUnionParam
11
7
  from mito_ai.utils.mito_server_utils import get_response_from_mito_server, stream_response_from_mito_server
12
8
  from mito_ai.utils.provider_utils import does_message_require_fast_model
13
- from openai.types.chat import ChatCompletionMessageParam
14
- from mito_ai.completions.models import AgentResponse, MessageType, ResponseFormatInfo, CompletionReply, CompletionStreamChunk, CompletionItem
9
+ from mito_ai.completions.models import AgentResponse, MessageType, ResponseFormatInfo, CompletionReply, CompletionStreamChunk
15
10
  from mito_ai.utils.schema import UJ_STATIC_USER_ID, UJ_USER_EMAIL
16
11
  from mito_ai.utils.db import get_user_field
17
- from mito_ai.utils.utils import is_running_test
18
- from mito_ai.utils.server_limits import check_mito_server_quota
19
- from .utils import _create_http_client
20
- from tornado.httpclient import AsyncHTTPClient
21
12
  from mito_ai.constants import MITO_ANTHROPIC_URL
22
13
 
23
14
  __user_email: Optional[str] = None
@@ -32,7 +23,7 @@ def _prepare_anthropic_request_data_and_headers(
32
23
  model: Union[str, None],
33
24
  max_tokens: int,
34
25
  temperature: float,
35
- system: Union[str, anthropic.NotGiven],
26
+ system: Union[str, anthropic.Omit],
36
27
  messages: List[MessageParam],
37
28
  message_type: MessageType,
38
29
  tools: Optional[List[ToolUnionParam]],
@@ -50,10 +41,11 @@ def _prepare_anthropic_request_data_and_headers(
50
41
  "model": model,
51
42
  "max_tokens": max_tokens,
52
43
  "temperature": temperature,
53
- "messages": messages
44
+ "messages": messages,
45
+ "betas": ["context-1m-2025-08-07"]
54
46
  }
55
- # Add system to inner_data only if it is not anthropic.NotGiven
56
- if not isinstance(system, anthropic.NotGiven):
47
+ # Add system to inner_data only if it is not anthropic.Omit
48
+ if not isinstance(system, anthropic.Omit):
57
49
  inner_data["system"] = system
58
50
  if tools:
59
51
  inner_data["tools"] = tools
@@ -76,7 +68,7 @@ async def get_anthropic_completion_from_mito_server(
76
68
  model: Union[str, None],
77
69
  max_tokens: int,
78
70
  temperature: float,
79
- system: Union[str, anthropic.NotGiven],
71
+ system: Union[str, anthropic.Omit],
80
72
  messages: List[MessageParam],
81
73
  tools: Optional[List[ToolUnionParam]],
82
74
  tool_choice: Optional[dict],
@@ -100,7 +92,7 @@ async def stream_anthropic_completion_from_mito_server(
100
92
  model: Union[str, None],
101
93
  max_tokens: int,
102
94
  temperature: float,
103
- system: Union[str, anthropic.NotGiven],
95
+ system: Union[str, anthropic.Omit],
104
96
  messages: List[MessageParam],
105
97
  stream: bool,
106
98
  message_type: MessageType,
@@ -133,7 +125,7 @@ def get_anthropic_completion_function_params(
133
125
  model: str,
134
126
  messages: List[MessageParam],
135
127
  max_tokens: int,
136
- system: Union[str, anthropic.NotGiven],
128
+ system: Union[str, anthropic.Omit],
137
129
  temperature: float = 0.0,
138
130
  tools: Optional[List[ToolUnionParam]] = None,
139
131
  tool_choice: Optional[dict] = None,
@@ -104,7 +104,7 @@ def telemetry_turned_on(key_type: Optional[str] = None) -> bool:
104
104
 
105
105
  return bool(telemetry)
106
106
 
107
- def identify(key_type: Optional[str] = None) -> None:
107
+ def identify(key_type: Optional[str] = None, is_electron: Optional[bool] = None) -> None:
108
108
  """
109
109
  Helper function for identifying a user. We just take
110
110
  their python version, mito version, and email.
@@ -125,6 +125,11 @@ def identify(key_type: Optional[str] = None) -> None:
125
125
  IS_DEV_MODE_PARAM: is_dev_mode(),
126
126
  UJ_FEEDBACKS_V2: feedbacks_v2
127
127
  }
128
+
129
+ if is_electron is not None:
130
+ # Only update field when we get info from the client. Don't default to False.
131
+ # becase we are only sending this info to the first completion_handler identify call.
132
+ params['is_mito_desktop'] = is_electron
128
133
 
129
134
  if not is_running_test():
130
135
  # TODO: If the user is in JupyterLite, we need to do some extra work.
@@ -362,11 +367,16 @@ def log_file_upload_attempt(
362
367
  def log_file_upload_failure(error: str) -> None:
363
368
  log("mito_ai_file_upload_failure", params={"error_message": error})
364
369
 
365
- def log_ai_completion_retry(key_type: Literal['mito_server_key', 'user_key'], message_type: MessageType, error: BaseException) -> None:
366
- log(MITO_AI_COMPLETION_RETRY, params={KEY_TYPE_PARAM: key_type, "message_type": message_type}, key_type=key_type, error=error)
370
+ def log_ai_completion_retry(key_type: Literal['mito_server_key', 'user_key'], thread_id: str, message_type: MessageType, error: BaseException) -> None:
371
+ log(MITO_AI_COMPLETION_RETRY, params={KEY_TYPE_PARAM: key_type, "message_type": message_type}, thread_id=thread_id, key_type=key_type, error=error)
367
372
 
368
- def log_ai_completion_error(key_type: Literal['mito_server_key', 'user_key'], message_type: MessageType, error: BaseException) -> None:
369
- log(MITO_AI_COMPLETION_ERROR, params={KEY_TYPE_PARAM: key_type, "message_type": message_type}, key_type=key_type, error=error)
373
+ def log_ai_completion_error(
374
+ key_type: Literal['mito_server_key', 'user_key'],
375
+ thread_id: str,
376
+ message_type: MessageType,
377
+ error: BaseException
378
+ ) -> None:
379
+ log(MITO_AI_COMPLETION_ERROR, params={KEY_TYPE_PARAM: key_type, "message_type": message_type}, thread_id=thread_id, key_type=key_type, error=error)
370
380
 
371
381
  def log_mito_server_free_tier_limit_reached(key_type: Literal['mito_server_key', 'user_key'], message_type: MessageType) -> None:
372
382
  log(MITO_SERVER_FREE_TIER_LIMIT_REACHED, params={KEY_TYPE_PARAM: key_type, "message_type": message_type}, key_type=key_type)