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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from typing import List, Tuple
|
|
5
|
+
import re
|
|
6
|
+
from anthropic.types import MessageParam
|
|
7
|
+
from mito_ai.streamlit_conversion.prompts.streamlit_system_prompt import streamlit_system_prompt
|
|
8
|
+
from mito_ai.utils.anthropic_utils import stream_anthropic_completion_from_mito_server
|
|
9
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER
|
|
10
|
+
from mito_ai.completions.models import MessageType
|
|
11
|
+
|
|
12
|
+
STREAMLIT_AI_MODEL = "claude-sonnet-4-5-20250929"
|
|
13
|
+
|
|
14
|
+
def extract_todo_placeholders(agent_response: str) -> List[str]:
|
|
15
|
+
"""Extract TODO placeholders from the agent's response"""
|
|
16
|
+
return [line.strip() for line in agent_response.split('\n') if MITO_TODO_PLACEHOLDER in line]
|
|
17
|
+
|
|
18
|
+
async def get_response_from_agent(message_to_agent: List[MessageParam]) -> str:
|
|
19
|
+
"""Gets the streaming response from the agent using the mito server"""
|
|
20
|
+
model = STREAMLIT_AI_MODEL
|
|
21
|
+
max_tokens = 64000 # TODO: If we move to haiku, we must reset this to 8192
|
|
22
|
+
temperature = 0.2
|
|
23
|
+
|
|
24
|
+
accumulated_response = ""
|
|
25
|
+
async for stream_chunk in stream_anthropic_completion_from_mito_server(
|
|
26
|
+
model = model,
|
|
27
|
+
max_tokens = max_tokens,
|
|
28
|
+
temperature = temperature,
|
|
29
|
+
system = streamlit_system_prompt,
|
|
30
|
+
messages = message_to_agent,
|
|
31
|
+
stream=True,
|
|
32
|
+
message_type=MessageType.STREAMLIT_CONVERSION,
|
|
33
|
+
reply_fn=None,
|
|
34
|
+
message_id=""
|
|
35
|
+
):
|
|
36
|
+
accumulated_response += stream_chunk
|
|
37
|
+
return accumulated_response
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
MITO_TODO_PLACEHOLDER = "# MITO_TODO_PLACEHOLDER"
|
|
5
|
+
|
|
6
|
+
search_replace_instructions = f"""
|
|
7
|
+
RESPONSE FORMAT: You can edit the existing code using the **SEARCH_REPLACE format** for exact string matching and replacement.
|
|
8
|
+
|
|
9
|
+
**STRUCTURE:**
|
|
10
|
+
```search_replace
|
|
11
|
+
>>>>>>> SEARCH
|
|
12
|
+
[exact code currently in the file]
|
|
13
|
+
=======
|
|
14
|
+
[new code to replace it with]
|
|
15
|
+
<<<<<<< REPLACE
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**COMPONENTS:**
|
|
19
|
+
```search_replace - This is the start of the search/replace block
|
|
20
|
+
- `>>>>>>> SEARCH` - Exact text that EXISTS NOW in the file (7 chevrons)
|
|
21
|
+
- `=======` - Separator between the search and replace blocks (7 equals signs)
|
|
22
|
+
- `<<<<<<< REPLACE` - Replacement text (7 chevrons)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
**CRITICAL RULES - READ CAREFULLY:**
|
|
27
|
+
|
|
28
|
+
1. **SEARCH = CURRENT STATE ONLY**
|
|
29
|
+
- The SEARCH block must contain ONLY code that currently exists in the file
|
|
30
|
+
- NEVER include new code, future code, or code you wish existed in the SEARCH block
|
|
31
|
+
- Copy exact text from the current file, character-for-character
|
|
32
|
+
|
|
33
|
+
2. **EXACT MATCHING REQUIRED**
|
|
34
|
+
- Every space, tab, newline must match perfectly
|
|
35
|
+
- Preserve exact indentation (spaces vs tabs)
|
|
36
|
+
- Include trailing newlines if present
|
|
37
|
+
- No approximations - even one character difference will fail
|
|
38
|
+
|
|
39
|
+
3. **SIZE LIMITS**
|
|
40
|
+
- There are no size limits to each search/replace block, however, it is generally preferable to keep the SEARCH blocks small and focused on one change.
|
|
41
|
+
- For large changes, use multiple smaller search/replace blocks
|
|
42
|
+
|
|
43
|
+
4. **UNIQUENESS**
|
|
44
|
+
- Include enough context to make the SEARCH block unique
|
|
45
|
+
- If text appears multiple times, add surrounding lines
|
|
46
|
+
- Ensure there's only ONE match in the file
|
|
47
|
+
|
|
48
|
+
5. **VERIFICATION CHECKLIST** (before generating each block):
|
|
49
|
+
✓ Is every line in my SEARCH block currently in the file?
|
|
50
|
+
✓ Did I copy the exact spacing and whitespace?
|
|
51
|
+
✓ Will this match exactly once?
|
|
52
|
+
|
|
53
|
+
6. **SEARCH REPLACE BLOCK STRUCTURE**
|
|
54
|
+
- You must adhere to to the exact search_replace structure as shown in the examples.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
**MULTIPLE REPLACEMENTS:**
|
|
59
|
+
- You can include multiple search/replace blocks in one response
|
|
60
|
+
- Each block is independent and processed separately
|
|
61
|
+
- Use separate ```search_replace blocks for each change
|
|
62
|
+
|
|
63
|
+
<Example 1: Updating existing content>
|
|
64
|
+
|
|
65
|
+
```search_replace
|
|
66
|
+
>>>>>>> SEARCH
|
|
67
|
+
st.title("Old Title")
|
|
68
|
+
=======
|
|
69
|
+
st.title("New Title")
|
|
70
|
+
<<<<<<< REPLACE
|
|
71
|
+
```
|
|
72
|
+
</Example 1>
|
|
73
|
+
|
|
74
|
+
<Example 2: Adding new content>
|
|
75
|
+
|
|
76
|
+
```search_replace
|
|
77
|
+
>>>>>>> SEARCH
|
|
78
|
+
st.title("My App")
|
|
79
|
+
=======
|
|
80
|
+
st.title("My App")
|
|
81
|
+
st.header("Welcome")
|
|
82
|
+
st.write("This is a test app")
|
|
83
|
+
<<<<<<< REPLACE
|
|
84
|
+
```
|
|
85
|
+
</Example 2>
|
|
86
|
+
|
|
87
|
+
<Example 3: Deleting existing content>
|
|
88
|
+
|
|
89
|
+
```search_replace
|
|
90
|
+
>>>>>>> SEARCH
|
|
91
|
+
st.write("Old message")
|
|
92
|
+
=======
|
|
93
|
+
<<<<<<< REPLACE
|
|
94
|
+
```
|
|
95
|
+
</Example 3>
|
|
96
|
+
|
|
97
|
+
<Example 4: Multiple replacements in one response>
|
|
98
|
+
|
|
99
|
+
```search_replace
|
|
100
|
+
>>>>>>> SEARCH
|
|
101
|
+
st.title("Old Title")
|
|
102
|
+
=======
|
|
103
|
+
st.title("New Title")
|
|
104
|
+
<<<<<<< REPLACE
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```search_replace
|
|
108
|
+
>>>>>>> SEARCH
|
|
109
|
+
st.write("Old message")
|
|
110
|
+
=======
|
|
111
|
+
st.write("New message")
|
|
112
|
+
<<<<<<< REPLACE
|
|
113
|
+
```
|
|
114
|
+
</Example 4>
|
|
115
|
+
|
|
116
|
+
<Example 5: Using extra context to identify the correct code to replace>
|
|
117
|
+
|
|
118
|
+
In the below example, assume that the code st.write("Old message") appears multiple times in the file, so we use extra context lines to identify the correct code to replace.
|
|
119
|
+
|
|
120
|
+
```search_replace
|
|
121
|
+
>>>>>>> SEARCH
|
|
122
|
+
# This is a unique comment
|
|
123
|
+
st.write("Old message")
|
|
124
|
+
=======
|
|
125
|
+
# This is a unique comment
|
|
126
|
+
st.write("New message")
|
|
127
|
+
<<<<<<< REPLACE
|
|
128
|
+
```
|
|
129
|
+
</Example 5>
|
|
130
|
+
|
|
131
|
+
<Example 6: Search/replace while respecting whitespace and indentation>
|
|
132
|
+
|
|
133
|
+
```search_replace
|
|
134
|
+
>>>>>>> SEARCH
|
|
135
|
+
data_list = [
|
|
136
|
+
{{'id': 1, 'name': 'Item A'}},
|
|
137
|
+
{MITO_TODO_PLACEHOLDER}: Add remaining entries from notebook
|
|
138
|
+
]
|
|
139
|
+
=======
|
|
140
|
+
data_list = [
|
|
141
|
+
{{'id': 1, 'name': 'Item A'}},
|
|
142
|
+
{{'id': 2, 'name': 'Item B'}},
|
|
143
|
+
{{'id': 3, 'name': 'Item C'}},
|
|
144
|
+
{{'id': 4, 'name': 'Item D'}}
|
|
145
|
+
]
|
|
146
|
+
<<<<<<< REPLACE
|
|
147
|
+
```
|
|
148
|
+
</Example 6>
|
|
149
|
+
|
|
150
|
+
<Example 7: Tab structure changes>
|
|
151
|
+
|
|
152
|
+
```search_replace
|
|
153
|
+
>>>>>>> SEARCH
|
|
154
|
+
tab1, tab2 = st.tabs(["Cat", "Dog"])
|
|
155
|
+
|
|
156
|
+
with tab1:
|
|
157
|
+
st.header("A cat")
|
|
158
|
+
st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
159
|
+
with tab2:
|
|
160
|
+
st.header("A dog")
|
|
161
|
+
st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
162
|
+
=======
|
|
163
|
+
st.header("A cat")
|
|
164
|
+
st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
165
|
+
st.header("A dog")
|
|
166
|
+
st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
167
|
+
<<<<<<< REPLACE
|
|
168
|
+
```
|
|
169
|
+
</Example 7>
|
|
170
|
+
|
|
171
|
+
Your response must consist **only** of valid search_replace blocks.
|
|
172
|
+
"""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
def add_line_numbers_to_code(code: str) -> str:
|
|
5
|
+
"""Add line numbers to the code"""
|
|
6
|
+
code_with_line_numbers = ""
|
|
7
|
+
for i, line in enumerate(code.split('\n'), 1):
|
|
8
|
+
code_with_line_numbers += f"{i:3d}: {line}\n"
|
|
9
|
+
|
|
10
|
+
return code_with_line_numbers
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from typing import List
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER
|
|
6
|
+
|
|
7
|
+
def get_streamlit_app_creation_prompt(notebook: List[dict]) -> str:
|
|
8
|
+
"""
|
|
9
|
+
This prompt is used to create a streamlit app from a notebook.
|
|
10
|
+
"""
|
|
11
|
+
return f"""Convert the following Jupyter notebook into a Streamlit application.
|
|
12
|
+
|
|
13
|
+
GOAL: Create a complete, runnable Streamlit app that accurately represents the notebook. It must completely convert the notebook.
|
|
14
|
+
|
|
15
|
+
TODO PLACEHOLDER RULES:
|
|
16
|
+
If you decide to leave any TODOs, you must mark them with {MITO_TODO_PLACEHOLDER}. You should use {MITO_TODO_PLACEHOLDER} instead of comments like the following:
|
|
17
|
+
- # ... (include all mappings from the notebook)
|
|
18
|
+
- # ... (include all violation codes from the notebook)
|
|
19
|
+
- # Fill in the rest of the code here
|
|
20
|
+
- # TODO: Add more code here
|
|
21
|
+
- # TODO: Add the visualization code here
|
|
22
|
+
|
|
23
|
+
For each TODO, use this exact format:
|
|
24
|
+
{MITO_TODO_PLACEHOLDER}: <specific description of what needs to be added>
|
|
25
|
+
|
|
26
|
+
IMPORTANT:
|
|
27
|
+
- The app must still be RUNNABLE even with placeholders
|
|
28
|
+
- Include enough sample data to show the structure
|
|
29
|
+
- Do NOT use placeholders for small/medium content - include it directly
|
|
30
|
+
- Do NOT use placeholders for file paths, imports, or core logic
|
|
31
|
+
- Only use placeholders when absolutely necessary. Add all of the content directly as much as possible.
|
|
32
|
+
|
|
33
|
+
<Example>
|
|
34
|
+
If the notebook has a list of dictionaries with 50 entries, you would write:
|
|
35
|
+
|
|
36
|
+
data = [
|
|
37
|
+
{{'id': 1, 'name': 'Item A', 'category': 'Type 1', 'value': 100}},
|
|
38
|
+
{{'id': 2, 'name': 'Item B', 'category': 'Type 2', 'value': 200}},
|
|
39
|
+
{MITO_TODO_PLACEHOLDER}: Add remaining entries from the data list
|
|
40
|
+
]
|
|
41
|
+
</Example>
|
|
42
|
+
|
|
43
|
+
Notebook to convert:
|
|
44
|
+
|
|
45
|
+
{notebook}
|
|
46
|
+
"""
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import search_replace_instructions
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
6
|
+
|
|
7
|
+
def get_streamlit_error_correction_prompt(error: str, streamlit_app_code: str) -> str:
|
|
8
|
+
|
|
9
|
+
existing_streamlit_app_code_with_line_numbers = add_line_numbers_to_code(streamlit_app_code)
|
|
10
|
+
|
|
11
|
+
return f"""You've created a Streamlit app, but it has an error in it when you try to run it.
|
|
12
|
+
|
|
13
|
+
Your job is to fix the error now. Only fix the specific error that you are instructed to fix now. Do not fix other error that that you anticipate. You will be asked to fix other errors later.
|
|
14
|
+
|
|
15
|
+
{search_replace_instructions}
|
|
16
|
+
|
|
17
|
+
===============================================
|
|
18
|
+
|
|
19
|
+
EXISTING STREAMLIT APP:
|
|
20
|
+
{existing_streamlit_app_code_with_line_numbers}
|
|
21
|
+
|
|
22
|
+
===============================================
|
|
23
|
+
|
|
24
|
+
Please create a search/replace block that corrects this error. Please keep your fix concise:
|
|
25
|
+
{error}
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from typing import List
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER, search_replace_instructions
|
|
6
|
+
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
7
|
+
|
|
8
|
+
def get_finish_todo_prompt(notebook: List[dict], existing_streamlit_app_code: str, todo_placeholder: str) -> str:
|
|
9
|
+
|
|
10
|
+
existing_streamlit_app_code_with_line_numbers = add_line_numbers_to_code(existing_streamlit_app_code)
|
|
11
|
+
|
|
12
|
+
return f"""You've already created the first draft of a Streamlit app representation of a Jupyter notebook, but you left yourself some TODOs marked as `{MITO_TODO_PLACEHOLDER}`.
|
|
13
|
+
|
|
14
|
+
**CRITICAL COMPLETION REQUIREMENT:**
|
|
15
|
+
You have ONE and ONLY ONE opportunity to complete this TODO. If you do not finish the entire task completely, the application will be broken and unusable. This is your final chance to get it right.
|
|
16
|
+
|
|
17
|
+
**COMPLETION RULES:**
|
|
18
|
+
1. **NEVER leave partial work** - If the TODO asks for a list with 100 items, provide ALL 100 items
|
|
19
|
+
2. **NEVER use placeholders** - This is your only opportunity to fulfill this TODO, so do not leave yourself another TODO.
|
|
20
|
+
3. **NEVER assume "good enough"** - Complete the task to 100% satisfaction
|
|
21
|
+
4. **If the task seems large, that's exactly why it needs to be done now** - This is your only chance
|
|
22
|
+
|
|
23
|
+
**HOW TO DETERMINE IF TASK IS COMPLETE:**
|
|
24
|
+
- If building a list/dictionary: Include ALL items that should be in the final data structure
|
|
25
|
+
- If creating functions: Implement ALL required functionality
|
|
26
|
+
- If converting a visualization: Copy over ALL of the visualization code from the notebook, including all styling and formatting.
|
|
27
|
+
|
|
28
|
+
{search_replace_instructions}
|
|
29
|
+
|
|
30
|
+
===============================================
|
|
31
|
+
|
|
32
|
+
Input Notebook that you are converting into the Streamlit app:
|
|
33
|
+
{notebook}
|
|
34
|
+
|
|
35
|
+
===============================================
|
|
36
|
+
|
|
37
|
+
EXISTING STREAMLIT APP:
|
|
38
|
+
{existing_streamlit_app_code_with_line_numbers}
|
|
39
|
+
|
|
40
|
+
===============================================
|
|
41
|
+
|
|
42
|
+
Please make the changes for this TODO. Only focus on this one TODO right now. You will be asked to fix others later:
|
|
43
|
+
{todo_placeholder}
|
|
44
|
+
|
|
45
|
+
"""
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
streamlit_system_prompt = """You are a code conversion specialist who converts Jupyter notebooks into Streamlit applications with ABSOLUTE FIDELITY.
|
|
5
|
+
|
|
6
|
+
ROLE AND EXPERTISE:
|
|
7
|
+
- Expert in Python, Jupyter notebooks, Streamlit, and data visualization
|
|
8
|
+
- Experienced in creating executive-ready dashboards for business stakeholders
|
|
9
|
+
- Skilled in translating technical analysis into clear, interactive presentations
|
|
10
|
+
|
|
11
|
+
TASK REQUIREMENTS:
|
|
12
|
+
1. Convert Jupyter notebook content into a complete Streamlit application (app.py)
|
|
13
|
+
2. Preserve ALL outputs from code cells and markdown cells as they appear in the notebook
|
|
14
|
+
3. Maintain the logical flow and structure of the original analysis
|
|
15
|
+
4. Create an executive-friendly dashboard suitable for company leadership
|
|
16
|
+
|
|
17
|
+
STREAMLIT IMPLEMENTATION GUIDELINES:
|
|
18
|
+
- Use appropriate Streamlit components (st.title, st.header, st.subheader, st.markdown, etc.)
|
|
19
|
+
- Display all visualizations using st.pyplot(), st.plotly_chart(), or st.altair_chart() as appropriate
|
|
20
|
+
- Do not convert database connections into Streamlit's secret.toml format. If the user inlined their database credentials, are importing from an environment variable, or reading from a connections file, assume that same approach will work in the streamlit app.
|
|
21
|
+
- Show dataframes and tables using st.dataframe() or st.table()
|
|
22
|
+
- Include all text explanations and insights from markdown cells
|
|
23
|
+
- Add interactive elements where beneficial (filters, selectors, etc.)
|
|
24
|
+
- Ensure professional styling and layout suitable for executives
|
|
25
|
+
- Just create the streamlit app code, do not include a _main_ function block. The file will be run directly using `streamlit run app.py`.
|
|
26
|
+
|
|
27
|
+
CRITICAL REQUIREMENTS:
|
|
28
|
+
1. **PRESERVE ALL CODE EXACTLY**: Every line of code, every data structure, every import must be included in full
|
|
29
|
+
2. **NO PLACEHOLDERS**: Never use comments like "# Add more data here" or "# Fill in the rest"
|
|
30
|
+
3. **NO SIMPLIFICATION**: Do not replace actual data with sample data or hardcoded examples
|
|
31
|
+
4. **COMPLETE DATA STRUCTURES**: If a notebook has a 1000-line dictionary, include all 1000 lines
|
|
32
|
+
5. **PRESERVE DATA LOADING**: If the notebook reads from files, the Streamlit app must read from the same files
|
|
33
|
+
6. **NO IMPROVIZAITION**: Do not provide your own interpretations of the analysis. Just convert the existing analysis into a streamlit app.
|
|
34
|
+
|
|
35
|
+
STYLE GUIDELINES:
|
|
36
|
+
- Create a professional, executive-friendly dashboard
|
|
37
|
+
- If there are variables in the notebook that the streamlit app viewer would likely want to configure, then use the appropriate streamlit component to allow them to do so. For examples, if the notebook has a variable called "start_date" and "end_date", then use the st.date_input component to allow the user to select the start and end dates.
|
|
38
|
+
- Do not use emojis unless they are in the notebook already
|
|
39
|
+
- Do not modify the graphs or analysis. If the notebook has a graph, use the same graph in the streamlit app.
|
|
40
|
+
- Always include the following code at the top of the file so the user does not use the wrong deploy button
|
|
41
|
+
```python
|
|
42
|
+
st.markdown(\"\"\"
|
|
43
|
+
<style>
|
|
44
|
+
#MainMenu {visibility: hidden;}
|
|
45
|
+
.stAppDeployButton {display:none;}
|
|
46
|
+
footer {visibility: hidden;}
|
|
47
|
+
.stMainBlockContainer {padding: 2rem 1rem 2rem 1rem;}
|
|
48
|
+
</style>
|
|
49
|
+
\"\"\", unsafe_allow_html=True)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
OUTPUT FORMAT:
|
|
53
|
+
- Output the complete, runnable app.py file.
|
|
54
|
+
- Do not output any extra text, just give the python code.
|
|
55
|
+
|
|
56
|
+
"""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from typing import List
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import search_replace_instructions
|
|
6
|
+
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
7
|
+
|
|
8
|
+
def get_update_existing_app_prompt(notebook: List[dict], streamlit_app_code: str, edit_prompt: str) -> str:
|
|
9
|
+
"""
|
|
10
|
+
This prompt is used to update an existing streamlit app.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
existing_streamlit_app_code_with_line_numbers = add_line_numbers_to_code(streamlit_app_code)
|
|
14
|
+
|
|
15
|
+
return f"""
|
|
16
|
+
|
|
17
|
+
GOAL: You've previously created a first draft of the Streamlit app. Now the user reviewed it and provided feedback.Update the existing streamlit app according to the feedback provided by the user. Use the input notebook to help you understand what code needs to be added, changed, or modified to fulfill the user's edit request.
|
|
18
|
+
|
|
19
|
+
**CRITICAL COMPLETION REQUIREMENT:**
|
|
20
|
+
You have ONE and ONLY ONE opportunity to complete this edit request. If you do not finish the entire task completely, the application will be broken and unusable. This is your final chance to get it right.
|
|
21
|
+
|
|
22
|
+
**COMPLETION RULES:**
|
|
23
|
+
1. **NEVER leave partial work** - If the edit request requires generating a list with 100 items, provide ALL 100 items.
|
|
24
|
+
2. **NEVER use placeholders** - This is your only opportunity to fulfill this edit request, so do not leave yourself another TODOs.
|
|
25
|
+
3. **NEVER assume "good enough"** - Complete the task to 100% satisfaction.
|
|
26
|
+
4. **If the task seems large, that's exactly why it needs to be done now** - This is your only chance
|
|
27
|
+
|
|
28
|
+
**HOW TO DETERMINE IF TASK IS COMPLETE:**
|
|
29
|
+
- If building a list/dictionary: Include ALL items that should be in the final data structure.
|
|
30
|
+
- If creating functions: Implement ALL required functionality.
|
|
31
|
+
- If converting a visualization: Copy over ALL of the visualization code from the notebook, including all styling and formatting.
|
|
32
|
+
|
|
33
|
+
{search_replace_instructions}
|
|
34
|
+
|
|
35
|
+
===============================================
|
|
36
|
+
|
|
37
|
+
INPUT NOTEBOOK:
|
|
38
|
+
{notebook}
|
|
39
|
+
|
|
40
|
+
===============================================
|
|
41
|
+
|
|
42
|
+
EXISTING STREAMLIT APP:
|
|
43
|
+
{existing_streamlit_app_code_with_line_numbers}
|
|
44
|
+
|
|
45
|
+
===============================================
|
|
46
|
+
|
|
47
|
+
USER EDIT REQUEST:
|
|
48
|
+
{edit_prompt}
|
|
49
|
+
|
|
50
|
+
"""
|
|
@@ -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 re
|
|
5
|
+
from typing import List, Tuple
|
|
6
|
+
|
|
7
|
+
from mito_ai.utils.error_classes import StreamlitConversionError
|
|
8
|
+
from mito_ai.utils.telemetry_utils import log
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def extract_search_replace_blocks(message_content: str) -> List[Tuple[str, str]]:
|
|
12
|
+
"""
|
|
13
|
+
Extract all search_replace blocks from Claude's response.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
List of tuples (search_text, replace_text) for each search/replace block
|
|
17
|
+
"""
|
|
18
|
+
if "```search_replace" not in message_content:
|
|
19
|
+
return []
|
|
20
|
+
|
|
21
|
+
pattern = r'```search_replace\n(.*?)```'
|
|
22
|
+
matches = re.findall(pattern, message_content, re.DOTALL)
|
|
23
|
+
|
|
24
|
+
search_replace_pairs = []
|
|
25
|
+
for match in matches:
|
|
26
|
+
# Split by the separator
|
|
27
|
+
if "=======" not in match:
|
|
28
|
+
continue
|
|
29
|
+
|
|
30
|
+
parts = match.split("=======", 1)
|
|
31
|
+
if len(parts) != 2:
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
search_part = parts[0]
|
|
35
|
+
replace_part = parts[1]
|
|
36
|
+
|
|
37
|
+
# Extract search text (after SEARCH marker)
|
|
38
|
+
if ">>>>>>> SEARCH" in search_part:
|
|
39
|
+
search_text = search_part.split(">>>>>>> SEARCH", 1)[1].strip()
|
|
40
|
+
else:
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
# Extract replace text (before REPLACE marker)
|
|
44
|
+
if "<<<<<<< REPLACE" in replace_part:
|
|
45
|
+
replace_text = replace_part.split("<<<<<<< REPLACE", 1)[0].strip()
|
|
46
|
+
else:
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
search_replace_pairs.append((search_text, replace_text))
|
|
50
|
+
|
|
51
|
+
return search_replace_pairs
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def apply_search_replace(text: str, search_replace_pairs: List[Tuple[str, str]]) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Apply search/replace operations to the given text.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
text : str
|
|
61
|
+
The original file contents.
|
|
62
|
+
search_replace_pairs : List[Tuple[str, str]]
|
|
63
|
+
List of (search_text, replace_text) tuples to apply.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
str
|
|
68
|
+
The updated contents after applying all search/replace operations.
|
|
69
|
+
|
|
70
|
+
Raises
|
|
71
|
+
------
|
|
72
|
+
ValueError
|
|
73
|
+
If a search text is not found or found multiple times.
|
|
74
|
+
"""
|
|
75
|
+
if not search_replace_pairs:
|
|
76
|
+
return text
|
|
77
|
+
|
|
78
|
+
result = text
|
|
79
|
+
|
|
80
|
+
for search_text, replace_text in search_replace_pairs:
|
|
81
|
+
# Count occurrences of search text
|
|
82
|
+
count = result.count(search_text)
|
|
83
|
+
|
|
84
|
+
if count == 0:
|
|
85
|
+
print("Search Text Not Found: ", repr(search_text))
|
|
86
|
+
raise StreamlitConversionError(f"Search text not found: {repr(search_text)}", error_code=500)
|
|
87
|
+
elif count > 1:
|
|
88
|
+
print("Search Text Found Multiple Times: ", repr(search_text))
|
|
89
|
+
log("mito_ai_search_text_found_multiple_times", params={"search_text": repr(search_text)}, key_type="mito_server_key")
|
|
90
|
+
|
|
91
|
+
# Perform the replacement
|
|
92
|
+
result = result.replace(search_text, replace_text, 1)
|
|
93
|
+
|
|
94
|
+
return result
|