mito-ai 0.1.33__py3-none-any.whl → 0.1.49__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. mito_ai/__init__.py +49 -9
  2. mito_ai/_version.py +1 -1
  3. mito_ai/anthropic_client.py +142 -67
  4. mito_ai/{app_builder → app_deploy}/__init__.py +1 -1
  5. mito_ai/app_deploy/app_deploy_utils.py +44 -0
  6. mito_ai/app_deploy/handlers.py +345 -0
  7. mito_ai/{app_builder → app_deploy}/models.py +35 -22
  8. mito_ai/app_manager/__init__.py +4 -0
  9. mito_ai/app_manager/handlers.py +167 -0
  10. mito_ai/app_manager/models.py +71 -0
  11. mito_ai/app_manager/utils.py +24 -0
  12. mito_ai/auth/README.md +18 -0
  13. mito_ai/auth/__init__.py +6 -0
  14. mito_ai/auth/handlers.py +96 -0
  15. mito_ai/auth/urls.py +13 -0
  16. mito_ai/chat_history/handlers.py +63 -0
  17. mito_ai/chat_history/urls.py +32 -0
  18. mito_ai/completions/completion_handlers/agent_execution_handler.py +1 -1
  19. mito_ai/completions/completion_handlers/chat_completion_handler.py +4 -4
  20. mito_ai/completions/completion_handlers/utils.py +99 -37
  21. mito_ai/completions/handlers.py +57 -20
  22. mito_ai/completions/message_history.py +9 -1
  23. mito_ai/completions/models.py +31 -7
  24. mito_ai/completions/prompt_builders/agent_execution_prompt.py +21 -2
  25. mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +8 -0
  26. mito_ai/completions/prompt_builders/agent_system_message.py +115 -42
  27. mito_ai/completions/prompt_builders/chat_name_prompt.py +6 -6
  28. mito_ai/completions/prompt_builders/chat_prompt.py +18 -11
  29. mito_ai/completions/prompt_builders/chat_system_message.py +4 -0
  30. mito_ai/completions/prompt_builders/prompt_constants.py +23 -4
  31. mito_ai/completions/prompt_builders/utils.py +72 -10
  32. mito_ai/completions/providers.py +81 -47
  33. mito_ai/constants.py +25 -24
  34. mito_ai/file_uploads/__init__.py +3 -0
  35. mito_ai/file_uploads/handlers.py +248 -0
  36. mito_ai/file_uploads/urls.py +21 -0
  37. mito_ai/gemini_client.py +44 -48
  38. mito_ai/log/handlers.py +10 -3
  39. mito_ai/log/urls.py +3 -3
  40. mito_ai/openai_client.py +30 -44
  41. mito_ai/path_utils.py +70 -0
  42. mito_ai/streamlit_conversion/agent_utils.py +37 -0
  43. mito_ai/streamlit_conversion/prompts/prompt_constants.py +172 -0
  44. mito_ai/streamlit_conversion/prompts/prompt_utils.py +10 -0
  45. mito_ai/streamlit_conversion/prompts/streamlit_app_creation_prompt.py +46 -0
  46. mito_ai/streamlit_conversion/prompts/streamlit_error_correction_prompt.py +28 -0
  47. mito_ai/streamlit_conversion/prompts/streamlit_finish_todo_prompt.py +45 -0
  48. mito_ai/streamlit_conversion/prompts/streamlit_system_prompt.py +56 -0
  49. mito_ai/streamlit_conversion/prompts/update_existing_app_prompt.py +50 -0
  50. mito_ai/streamlit_conversion/search_replace_utils.py +94 -0
  51. mito_ai/streamlit_conversion/streamlit_agent_handler.py +144 -0
  52. mito_ai/streamlit_conversion/streamlit_utils.py +85 -0
  53. mito_ai/streamlit_conversion/validate_streamlit_app.py +105 -0
  54. mito_ai/streamlit_preview/__init__.py +6 -0
  55. mito_ai/streamlit_preview/handlers.py +111 -0
  56. mito_ai/streamlit_preview/manager.py +152 -0
  57. mito_ai/streamlit_preview/urls.py +22 -0
  58. mito_ai/streamlit_preview/utils.py +29 -0
  59. mito_ai/tests/chat_history/test_chat_history.py +211 -0
  60. mito_ai/tests/completions/completion_handlers_utils_test.py +190 -0
  61. mito_ai/tests/deploy_app/test_app_deploy_utils.py +89 -0
  62. mito_ai/tests/file_uploads/__init__.py +2 -0
  63. mito_ai/tests/file_uploads/test_handlers.py +282 -0
  64. mito_ai/tests/message_history/test_generate_short_chat_name.py +0 -4
  65. mito_ai/tests/message_history/test_message_history_utils.py +103 -23
  66. mito_ai/tests/open_ai_utils_test.py +18 -22
  67. mito_ai/tests/providers/test_anthropic_client.py +447 -0
  68. mito_ai/tests/providers/test_azure.py +2 -6
  69. mito_ai/tests/providers/test_capabilities.py +120 -0
  70. mito_ai/tests/{test_gemini_client.py → providers/test_gemini_client.py} +40 -36
  71. mito_ai/tests/providers/test_mito_server_utils.py +448 -0
  72. mito_ai/tests/providers/test_model_resolution.py +130 -0
  73. mito_ai/tests/providers/test_openai_client.py +57 -0
  74. mito_ai/tests/providers/test_provider_completion_exception.py +66 -0
  75. mito_ai/tests/providers/test_provider_limits.py +42 -0
  76. mito_ai/tests/providers/test_providers.py +382 -0
  77. mito_ai/tests/providers/test_retry_logic.py +389 -0
  78. mito_ai/tests/providers/test_stream_mito_server_utils.py +140 -0
  79. mito_ai/tests/providers/utils.py +85 -0
  80. mito_ai/tests/streamlit_conversion/__init__.py +3 -0
  81. mito_ai/tests/streamlit_conversion/test_apply_search_replace.py +240 -0
  82. mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +246 -0
  83. mito_ai/tests/streamlit_conversion/test_streamlit_utils.py +193 -0
  84. mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +112 -0
  85. mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +118 -0
  86. mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +292 -0
  87. mito_ai/tests/test_constants.py +31 -3
  88. mito_ai/tests/test_telemetry.py +12 -0
  89. mito_ai/tests/user/__init__.py +2 -0
  90. mito_ai/tests/user/test_user.py +120 -0
  91. mito_ai/tests/utils/test_anthropic_utils.py +6 -6
  92. mito_ai/user/handlers.py +45 -0
  93. mito_ai/user/urls.py +21 -0
  94. mito_ai/utils/anthropic_utils.py +55 -121
  95. mito_ai/utils/create.py +17 -1
  96. mito_ai/utils/error_classes.py +42 -0
  97. mito_ai/utils/gemini_utils.py +39 -94
  98. mito_ai/utils/message_history_utils.py +7 -4
  99. mito_ai/utils/mito_server_utils.py +242 -0
  100. mito_ai/utils/open_ai_utils.py +38 -155
  101. mito_ai/utils/provider_utils.py +49 -0
  102. mito_ai/utils/server_limits.py +1 -1
  103. mito_ai/utils/telemetry_utils.py +137 -5
  104. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +102 -100
  105. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/package.json +4 -2
  106. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +3 -1
  107. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +2 -2
  108. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.281f4b9af60d620c6fb1.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js +15948 -8403
  109. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.8f1845da6bf2b128c049.js.map +1 -0
  110. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +198 -0
  111. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +1 -0
  112. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.4f1d00fd0c58fcc05d8d.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.8b24b5b3b93f95205b56.js +58 -33
  113. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.8b24b5b3b93f95205b56.js.map +1 -0
  114. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.06083e515de4862df010.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +10 -2
  115. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +1 -0
  116. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js +533 -0
  117. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_apis_signOut_mjs-node_module-75790d.688c25857e7b81b1740f.js.map +1 -0
  118. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js +6941 -0
  119. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_auth_dist_esm_providers_cognito_tokenProvider_tokenProvider_-72f1c8.a917210f057fcfe224ad.js.map +1 -0
  120. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +1021 -0
  121. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +1 -0
  122. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +59698 -0
  123. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +1 -0
  124. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js +7440 -0
  125. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_react-dom_client_js-node_modules_aws-amplify_ui-react_dist_styles_css.b43d4249e4d3dac9ad7b.js.map +1 -0
  126. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.9795f79265ddb416864b.js → mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +2 -240
  127. mito_ai-0.1.49.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +1 -0
  128. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/METADATA +5 -2
  129. mito_ai-0.1.49.dist-info/RECORD +205 -0
  130. mito_ai/app_builder/handlers.py +0 -218
  131. mito_ai/tests/providers_test.py +0 -438
  132. mito_ai/tests/test_anthropic_client.py +0 -270
  133. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.281f4b9af60d620c6fb1.js.map +0 -1
  134. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.4f1d00fd0c58fcc05d8d.js.map +0 -1
  135. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/style_index_js.06083e515de4862df010.js.map +0 -1
  136. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_html2canvas_dist_html2canvas_js.ea47e8c8c906197f8d19.js +0 -7842
  137. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_html2canvas_dist_html2canvas_js.ea47e8c8c906197f8d19.js.map +0 -1
  138. mito_ai-0.1.33.data/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.9795f79265ddb416864b.js.map +0 -1
  139. mito_ai-0.1.33.dist-info/RECORD +0 -134
  140. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
  141. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
  142. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +0 -0
  143. {mito_ai-0.1.33.data → mito_ai-0.1.49.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +0 -0
  144. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/WHEEL +0 -0
  145. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/entry_points.txt +0 -0
  146. {mito_ai-0.1.33.dist-info → mito_ai-0.1.49.dist-info}/licenses/LICENSE +0 -0
@@ -49,17 +49,21 @@ Format:
49
49
  type: 'modification'
50
50
  id: str,
51
51
  code: str
52
+ code_summary: str
52
53
  cell_type: 'code' | 'markdown'
53
- }}
54
- get_cell_output_cell_id: None,
55
- next_steps: None
54
+ }},
55
+ analysis_assumptions: Optional[List[str]]
56
56
  }}
57
57
 
58
58
  Important information:
59
59
  1. The id is the id of the code cell that you want to update. The id MUST already be part of the original Jupyter Notebook that your colleague shared with you.
60
60
  2. The message is a short summary of your thought process that helped you decide what to update in cell_update.
61
61
  3. The code should be the full contents of that updated code cell. The code that you return will overwrite the existing contents of the code cell so it must contain all necessary code.
62
- 4. Important: Only use the CELL_UPDATE tool if you want to add/modify a notebook cell in response to the user's request. If the user is just sending you a friendly greeting or asking you a question about yourself, you SHOULD NOT USE A CELL_UPDATE tool because it does not require modifying the notebook. Instead, just use the FINISHED_TASK response.
62
+ 4. The code_summary must be a very short phrase (1–5 words maximum) that begins with a verb ending in "-ing" (e.g., "Loading data", "Filtering rows", "Calculating average", "Plotting revenue"). Avoid full sentences or explanations—this should read like a quick commit message or code label, not a description.
63
+ 5. Important: Only use the CELL_UPDATE tool if you want to add/modify a notebook cell in response to the user's request. If the user is just sending you a friendly greeting or asking you a question about yourself, you SHOULD NOT USE A CELL_UPDATE tool because it does not require modifying the notebook. Instead, just use the FINISHED_TASK response.
64
+ 6. The analysis_assumptions is an optional list of critical assumptions that you made about the data or analysis approach. The assumptions you list here will be displayed to the user so that they can confirm or correct the assumptions. For example: ["NaN values in the impressions column represent 0 impressions", "Only crashes with pedestrian or cyclist fatalities are considered fatal crashes", "Intervention priority combines both volume and severity to identify maximum impact opportunities"].
65
+ 7. Only include important data and analytical assumptions that if incorrect would fundamentally change your analysis conclusions. These should be data handling decisions, methodological choices, and definitional boundaries. Do not include: obvious statements ("Each record is counted once"), result interpretation guidance ("Gaps in the plot represent zero values"), display choices ("Data is sorted for clarity"), internal reasoning ("Bar chart is better than line plot"), or environment assumptions ("Library X is installed"). Prioritize quality over quantity - include only the most critical assumptions or omit the field entirely if there are no critical assumptions made in this step that have not already be shared with the user. If you ever doubt whether an assumption is critical enough to be shared with the user as an assumption, don't include it. Most messages should not include an assumption.
66
+ 8. Do not include the same assumption or variations of the same assumption multiple times in the same conversation. Once you have presented the assumption to the user, they will already have the opportunity to confirm or correct it so do not include it again.
63
67
 
64
68
  #### Cell Addition:
65
69
  When you want to add a new cell to the notebook, respond in this format
@@ -72,17 +76,21 @@ Format:
72
76
  type: 'new'
73
77
  index: int
74
78
  code: str
79
+ code_summary: str
75
80
  cell_type: 'code' | 'markdown'
76
- }}
77
- get_cell_output_cell_id: None,
78
- next_steps: None
81
+ }},
82
+ analysis_assumptions: Optional[List[str]]
79
83
  }}
80
84
 
81
85
  Important information:
82
86
  1. The index should be the 0-index position of where you want the new code cell to be added in the notebook.
83
87
  2. The message is a short summary of your thought process that helped you decide what to update in cell_update.
84
88
  3. The code should be the full contents of that updated code cell. The code that you return will overwrite the existing contents of the code cell so it must contain all necessary code.
85
- 4. The cell_type should only be 'markdown' if there is no code to add. There may be times where the code has comments. These are still code cells and should have the cell_type 'code'. Any cells that are labeled 'markdown' will be converted to markdown cells by the user.
89
+ 4. code_summary must be a very short phrase (1–5 words maximum) that begins with a verb ending in "-ing" (e.g., "Loading data", "Filtering rows", "Calculating average", "Plotting revenue"). Avoid full sentences or explanations—this should read like a quick commit message or code label, not a description.
90
+ 5. The cell_type should only be 'markdown' if there is no code to add. There may be times where the code has comments. These are still code cells and should have the cell_type 'code'. Any cells that are labeled 'markdown' will be converted to markdown cells by the user.
91
+ 6. The analysis_assumptions is an optional list of critical assumptions that you made about the data or analysis approach. The assumptions you list here will be displayed to the user so that they can confirm or correct the assumptions. For example: ["NaN values in the impressions column represent 0 impressions", "Only crashes with pedestrian or cyclist fatalities are considered fatal crashes", "Intervention priority combines both volume and severity to identify maximum impact opportunities"].
92
+ 7. Only include important data and analytical assumptions that if incorrect would fundamentally change your analysis conclusions. These should be data handling decisions, methodological choices, and definitional boundaries. Do not include: obvious statements ("Each record is counted once"), result interpretation guidance ("Gaps in the plot represent zero values"), display choices ("Data is sorted for clarity"), internal reasoning ("Bar chart is better than line plot"), or environment assumptions ("Library X is installed"). Prioritize quality over quantity - include only the most critical assumptions or omit the field entirely if there are no critical assumptions made in this step that have not already be shared with the user. If you ever doubt whether an assumption is critical enough to be shared with the user as an assumption, don't include it. Most messages should not include an assumption.
93
+ 8. Do not include the same assumption or variations of the same assumption multiple times in the same conversation. Once you have presented the assumption to the user, they will already have the opportunity to confirm or correct it so do not include it again.
86
94
 
87
95
  <Cell Modification Example>
88
96
  Jupyter Notebook:
@@ -121,15 +129,14 @@ Convert the transaction_date column to datetime and then multiply the total_pric
121
129
  Output:
122
130
  {{
123
131
  type: 'cell_update',
124
- cell_type: 'code',
132
+ message: "I'll convert the transaction_date column to datetime and multiply total_price by the multiplier.",
125
133
  cell_update: {{
126
- type: 'modification'
134
+ type: 'modification',
127
135
  id: 'c68fdf19-db8c-46dd-926f-d90ad35bb3bc',
128
136
  code: "import pandas as pd\\nsales_df = pd.read_csv('./sales.csv')\\nloan_multiplier = 1.5\\nsales_df['transaction_date'] = pd.to_datetime(sales_df['transaction_date'])\\nsales_df['total_price'] = sales_df['total_price'] * sales_multiplier",
137
+ code_summary: "Converting the transaction_date column",
129
138
  cell_type: 'code'
130
- }},
131
- get_cell_output_cell_id: None,
132
- next_steps: None
139
+ }}
133
140
  }}
134
141
 
135
142
  </Cell Modification Example>
@@ -170,14 +177,14 @@ Graph the total_price for each sale
170
177
  Output:
171
178
  {{
172
179
  type: 'cell_update',
173
- message: "I'll create a graph with using matplotlib with sale `index` on the x axis and `total_price` on the y axis.",
180
+ message: "I'll create a graph using matplotlib with sale index on the x axis and total_price on the y axis.",
174
181
  cell_update: {{
175
- type: 'add'
176
- index: 2
177
- code: "import matplotlib.pyplot as plt\n\nplt.bar(sales_df.index, sales_df['total_price'])\nplt.title('Total Price per Sale')\nplt.xlabel('Transaction Number')\nplt.ylabel('Sales Price ($)')\nplt.show()"
178
- }},
179
- get_cell_output_cell_id: None,
180
- next_steps: None
182
+ type: 'new',
183
+ index: 2,
184
+ code: "import matplotlib.pyplot as plt\n\nplt.bar(sales_df.index, sales_df['total_price'])\nplt.title('Total Price per Sale')\nplt.xlabel('Transaction Number')\nplt.ylabel('Sales Price ($)')\nplt.show()",
185
+ code_summary: "Plotting total_price",
186
+ cell_type: 'code'
187
+ }}
181
188
  }}
182
189
 
183
190
  </Cell Addition Example>
@@ -191,9 +198,7 @@ When you want to get a base64 encoded version of a cell's output, respond with t
191
198
  {{
192
199
  type: 'get_cell_output',
193
200
  message: str,
194
- get_cell_output_cell_id: str,
195
- cell_update: None,
196
- next_steps: Optional[List[str]]
201
+ get_cell_output_cell_id: str
197
202
  }}
198
203
 
199
204
  Important information:
@@ -203,6 +208,74 @@ Important information:
203
208
  ===='''
204
209
  }
205
210
 
211
+ TOOL: RUN_ALL_CELLS
212
+
213
+ When you want to execute all cells in the notebook from top to bottom, respond with this format:
214
+
215
+ {{
216
+ type: 'run_all_cells',
217
+ message: str
218
+ }}
219
+
220
+ Important information:
221
+ 1. Use this tool when you encounter a NameError. For example, if you get an error like "NameError: name 'prompts_df' is not defined", you should use this tool to run all cells from the top of the notebook to the bottom to bring the variable into scope.
222
+ 2. Note that if the name error persists even after using run_all_cells, it means that the variable is not defined in the notebook and you should not reuse this tool.
223
+ 3. Additionally, this tool could also be used to refresh the notebook state.
224
+ 4. If running all cells results in an error, the system will automatically handle the error through the normal error fixing process.
225
+ 5. Do not use this tool repeatedly if it continues to produce errors - instead, focus on fixing the specific error that occurred.
226
+ ====
227
+
228
+ TOOL: CREATE_STREAMLIT_APP
229
+
230
+ When you want to create a new Streamlit app from the current notebook, respond with this format:
231
+
232
+ {{
233
+ type: 'create_streamlit_app',
234
+ message: str
235
+ }}
236
+
237
+ Important information:
238
+ 1. The message is a short summary of why you're creating the Streamlit app.
239
+ 2. Only use this tool when the user explicitly asks to create or preview a Streamlit app AND no Streamlit app is currently open.
240
+ 3. This tool creates a new app from scratch - use EDIT_STREAMLIT_APP tool if the user is asking you to edit, update, or modify an app that already exists.
241
+ 4. Using this tool will automatically open the app so the user can see a preview of the app.
242
+ 5. When you use this tool, assume that it successfully created the Streamlit app unless the user explicitly tells you otherwise. The app will remain open so that the user can view it until the user decides to close it. You do not need to continually use the create_streamlit_app tool to keep the app open.
243
+
244
+ <Example>
245
+
246
+ Your task: Show me my notebook as an app.
247
+
248
+ Output:
249
+ {{
250
+ type: 'create_streamlit_app',
251
+ message: "I'll convert your notebook into an app."
252
+ }}
253
+
254
+ The user will see a preview of the app and because you fulfilled your task, you can next respond with a FINISHED_TASK tool message.
255
+
256
+ <Example>
257
+
258
+ ====
259
+
260
+ TOOL: EDIT_STREAMLIT_APP
261
+
262
+ When you want to edit an existing Streamlit app, respond with this format:
263
+
264
+ {{
265
+ type: 'edit_streamlit_app',
266
+ message: str,
267
+ edit_streamlit_app_prompt: str
268
+ }}
269
+
270
+ Important information:
271
+ 1. The message is a short summary of why you're editing the Streamlit app.
272
+ 2. The edit_streamlit_app_prompt is REQUIRED and must contain specific instructions for the edit (e.g., "Make the title text larger", "Change the chart colors to blue", "Add a sidebar with filters").
273
+ 3. Only use this tool when the user asks to edit, update, or modify a Streamlit app.
274
+ 4. The app does not need to already be open for you to use the tool. Using this tool will automatically open the streamlit app after applying the changes so the user can view it. You do not need to call the create_streamlit_app tool first.
275
+ 5. When you use this tool, assume that it successfully edited the Streamlit app unless the user explicitly tells you otherwise. The app will remain open so that the user can view it until the user decides to close it.
276
+
277
+ ====
278
+
206
279
  TOOL: FINISHED_TASK
207
280
 
208
281
  When you have completed the user's task, respond with a message in this format:
@@ -210,27 +283,24 @@ When you have completed the user's task, respond with a message in this format:
210
283
  {{
211
284
  type: 'finished_task',
212
285
  message: str,
213
- get_cell_output_cell_id: None,
214
- cell_update: None,
215
286
  next_steps: Optional[List[str]]
216
287
  }}
217
288
 
218
289
  Important information:
219
290
  1. The message is a short summary of the ALL the work that you've completed on this task. It should not just refer to the final message. It could be something like "I've completed the sales strategy analysis by exploring key relationships in the data and summarizing creating a report with three recommendations to boost sales.""
220
291
  2. The message should include citations for any insights that you shared with the user.
221
- 3. The next_steps is an optional list of 2 or 3 suggested follow-up tasks or analyses that the user might want to perform next. These should be concise, actionable suggestions that build on the work you've just completed. For example: ["Visualize the results", "Export the cleaned data to CSV", "Perform statistical analysis on the key metrics"].
222
- 4. The next_steps should be as relevant to the user's actual task as possible. Try your best not to make generic suggestions like "Analyze the data" or "Visualize the results". For example, if the user just asked you to calculate LTV of their customers, you might suggest the following next steps: ["Graph key LTV drivers: churn and average transaction value", "Visualize LTV per customer age group"].
292
+ 3. The next_steps is an optional list of 2 or 3 suggested follow-up tasks or analyses that the user might want to perform next. These should be concise, actionable suggestions that build on the work you've just completed. For example: ["Export the cleaned data to CSV", "Analyze revenue per customer", "Convert notebook into an app"].
293
+ 4. The next_steps should be as relevant to the user's actual task as possible. Try your best not to make generic suggestions like "Analyze the data" or "Visualize the results". For example, if the user just asked you to calculate LTV of their customers, you might suggest the following next steps: ["Graph key LTV drivers: churn and average transaction value", "Visualize LTV per age group"].
223
294
  5. If you are not sure what the user might want to do next, err on the side of suggesting next steps instead of making an assumption and using more CELL_UPDATES.
224
295
  6. If the user's task doesn't involve creating or modifying a code cell, you should respond with a FINISHED_TASK response.
225
296
  7. If the user is just sending a friendly greeting (like "Hello", "Hi", "Hey", "How are you?", "What can you help me with?", etc.), you must respond with a FINISHED_TASK response message with a friendly message like this: "Hello! I'm Mito AI, your AI assistant for data analysis and Python programming in Jupyter notebooks. I can help you analyze datasets, create visualizations, clean data, and much more. What would you like to work on today?"
297
+ 8. Do not include any analysis_assumptions in the FINISHED_TASK response.
226
298
 
227
299
  <Finished Task Example 1>
228
300
 
229
301
  {{
230
302
  type: 'finished_task',
231
303
  message: "Revenue analysis complete: total sales reached $2.3M with 34% growth in Q4[MITO_CITATION:abc123:2-3], while premium products generated 67% of profit margins[MITO_CITATION:xyz456:5]. The customer segmentation workflow identified three distinct buying patterns driving conversion rates[MITO_CITATION:def456:8-12].",
232
- get_cell_output_cell_id: None,
233
- cell_update: None,
234
304
  next_steps: ["Graph sales by product category", "Identify seasonal patterns in data", "Find the top 3 performing products"]
235
305
  }}
236
306
 
@@ -243,10 +313,7 @@ User message: "Hi"
243
313
  Output:
244
314
  {{
245
315
  type: 'finished_task',
246
- message: "Hey there! I'm Mito AI. How can I help you today?",
247
- get_cell_output_cell_id: None,
248
- cell_update: None,
249
- next_steps: None
316
+ message: "Hey there! I'm Mito AI. How can I help you today?"
250
317
  }}
251
318
 
252
319
  </Finished Task Example 2>
@@ -306,11 +373,11 @@ Output:
306
373
  type: 'cell_update',
307
374
  message: "I'll calculate two new variables all_time_high_date and all_time_high_price.",
308
375
  cell_update: {{
309
- type: 'add'
310
- index: 2
311
- code: "all_time_high_row_idx = tesla_stock_prices_df['closing_price'].idxmax()\nall_time_high_date = tesla_stock_prices_df.at[all_time_high_row_idx, 'Date']\nall_time_high_price = tesla_stock_prices_df.at[all_time_high_row_idx, 'closing_price']"
312
- }},
313
- get_cell_output_cell_id: None
376
+ type: 'new',
377
+ index: 2,
378
+ code: "all_time_high_row_idx = tesla_stock_prices_df['closing_price'].idxmax()\nall_time_high_date = tesla_stock_prices_df.at[all_time_high_row_idx, 'Date']\nall_time_high_price = tesla_stock_prices_df.at[all_time_high_row_idx, 'closing_price']",
379
+ code_summary: "Calculating all time high"
380
+ }}
314
381
  }}
315
382
 
316
383
  ### User Message 2
@@ -357,8 +424,6 @@ Output:
357
424
  {{
358
425
  type: 'finished_task',
359
426
  message: "The all time high tesla stock closing price was $265.91 [MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:2] on 2025-03-16 [MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:1]",
360
- get_cell_output_cell_id: None,
361
- cell_update: None,
362
427
  next_steps: ["Create a visualization of Tesla's stock price over time", "Calculate the percentage change from the lowest to highest price", "Analyze the volatility of Tesla's stock"]
363
428
  }}
364
429
 
@@ -377,7 +442,9 @@ As you are guiding the user through the process of completing the task, send the
377
442
 
378
443
  The user is a beginning Python user, so you will need to be careful to send them only small steps to complete. Don't try to complete the task in a single response to the user. Instead, each message you send to the user should only contain a single, small step towards the end goal. When the user has completed the step, they will let you know that they are ready for the next step.
379
444
 
380
- You will keep working in the following iterative format until you have decided that you have finished the user's request. When you decide that you have finished the user's request, respond with a FINISHED_TASK tool message. Otherwise, if you have not finished the user's request, respond with a CELL_UPDATE {OR_GET_CELL_OUTPUT} tool message. When you respond with a CELL_UPDATE, the user will apply the CELL_UPDATE to the notebook and run the new code cell. The user will then send you a message with an updated version of the variables defined in the kernel, code in the notebook, and files in the current directory. In addition, the user will check if the code you provided produced an errored when executed. If it did produce an error, the user will share the error message with you.
445
+ You will keep working in the following iterative format until you have decided that you have finished the user's request. When you decide that you have finished the user's request, respond with a FINISHED_TASK tool message. Otherwise, if you have not finished the user's request, respond with one of your other tools.
446
+
447
+ When you respond with a CELL_UPDATE, the user will apply the CELL_UPDATE to the notebook and run the new code cell. The user will then send you a message with an updated version of the variables defined in the kernel, code in the notebook, and files in the current directory. In addition, the user will check if the code you provided produced an errored when executed. If it did produce an error, the user will share the error message with you.
381
448
 
382
449
  Whenever you get a message back from the user, you should:
383
450
  1. Ask yourself if the previous message you sent to the user was correct. You can answer this question by reviewing the updated code, variables, or output of the cell if you requested it.
@@ -396,4 +463,10 @@ REMEMBER, YOU ARE GOING TO COMPLETE THE USER'S TASK OVER THE COURSE OF THE ENTIR
396
463
  - If you are happy with the analysis, refer back to the original task provided by the user to decide your next steps. In this example, it is to graph the results, so you will send a CellAddition to construct the graph.
397
464
  - Wait for the user to send you back the updated variables and notebook state.
398
465
  {'' if not isChromeBrowser else '- Send a GET_CELL_OUTPUT tool message to get the output of the cell you just created and check if you can improve the graph to make it more readable, informative, or professional.'}
399
- - If after reviewing the updates you decide that you've completed the task, send a FINISHED_TASK tool message."""
466
+ - If after reviewing the updates you decide that you've completed the task, send a FINISHED_TASK tool message.
467
+
468
+ ====
469
+
470
+ OTHER USEFUL INFORMATION:
471
+ 1. When importing matplotlib, write the code `%matplotlib inline` to make sure the graphs render in Jupyter
472
+ 2. The active cell ID is shared with you so that when the user refers to "this cell" or similar phrases, you know which cell they mean. However, you are free to edit any cell that you see fit."""
@@ -3,13 +3,13 @@
3
3
 
4
4
  def create_chat_name_prompt(user_message: str, assistant_message: str) -> str:
5
5
  prompt = f"""Create a short name for the chat thread based on the first user message
6
- and the first LLM response. Reply ONLY with the short title (max 40 chars). Don't add any extra text.
7
-
8
- Don't include that its a Python project in the chat.
6
+ and the first LLM response. Reply ONLY with the short title (max 40 chars). Don't add any extra text.
7
+
8
+ Don't include that its a Python project in the chat.
9
9
 
10
- User Message: {user_message}
10
+ User Message: {user_message}
11
11
 
12
- Assistant Message: {assistant_message}
13
- """
12
+ Assistant Message: {assistant_message}
13
+ """
14
14
 
15
15
  return prompt
@@ -1,30 +1,35 @@
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
- from typing import List, Optional
4
+ from typing import List, Optional, Dict
5
5
  from mito_ai.completions.prompt_builders.prompt_constants import (
6
6
  ACTIVE_CELL_ID_SECTION_HEADING,
7
7
  CHAT_CODE_FORMATTING_RULES,
8
8
  FILES_SECTION_HEADING,
9
9
  VARIABLES_SECTION_HEADING,
10
10
  CODE_SECTION_HEADING,
11
- get_active_cell_output_str
11
+ get_active_cell_output_str,
12
12
  )
13
- from mito_ai.completions.prompt_builders.utils import get_rules_str
13
+ from mito_ai.completions.prompt_builders.utils import (
14
+ get_rules_str,
15
+ get_selected_context_str,
16
+ )
17
+
14
18
 
15
19
  def create_chat_prompt(
16
20
  variables: List[str],
17
21
  files: List[str],
18
- active_cell_code: str,
22
+ active_cell_code: str,
19
23
  active_cell_id: str,
20
24
  has_active_cell_output: bool,
21
25
  input: str,
22
- selected_rules: Optional[List[str]] = None
26
+ additional_context: Optional[List[Dict[str, str]]] = None,
23
27
  ) -> str:
24
- variables_str = '\n'.join([f"{variable}" for variable in variables])
25
- files_str = '\n'.join([f"{file}" for file in files])
26
- rules_str = get_rules_str(selected_rules)
27
-
28
+ variables_str = "\n".join([f"{variable}" for variable in variables])
29
+ files_str = "\n".join([f"{file}" for file in files])
30
+ selected_context_str = get_selected_context_str(additional_context)
31
+ rules_str = get_rules_str(additional_context)
32
+
28
33
  prompt = f"""{rules_str}
29
34
 
30
35
  Help me complete the following task. I will provide you with a set of variables, existing code, and a task to complete.
@@ -101,9 +106,11 @@ Hey there! I'm Mito AI. How can I help you today?
101
106
  {active_cell_code}
102
107
  ```
103
108
 
109
+ {selected_context_str}
110
+
104
111
  {get_active_cell_output_str(has_active_cell_output)}
105
112
 
106
113
  Your task: {input}
107
114
  """
108
-
109
- return prompt
115
+
116
+ return prompt
@@ -21,6 +21,10 @@ There are three possible types of responses you might give:
21
21
  2. Explanation/Analysis: If the task does not require a code update, it might instead require you to provide an explanation of existing code or data, provide an analysis of the the data or chart.
22
22
  3. Friendly Response: If the user is just asking a question, saying hi, or you're just chatting, respond with a friendly response and do not return any code.
23
23
 
24
+ Other useful information:
25
+ 1. The user has two types of modes that they can collaborate with you in: Chat Mode (this mode) and agent mode. Chat mode gives the user more control over the edits made to the notebook and only edits the active cell. Agent mode gives you more autonomy over completing the user's task across mulitple messages. In agent mode, you can edit or create new cells, see the entire notebook, automatically run the code you write, and more.
26
+ 2. If the user asks you to generate a dashboard, app, or streamlit app for them, you should tell them that they must use Agent mode to complete the task. You are not able to automatically switch the user to agent mode, but they can switch to it themselves by using the Chat/Agent mode toggle in the bottom left corner of the Ai taskpane.
27
+
24
28
  ====
25
29
  {CITATION_RULES}
26
30
 
@@ -19,6 +19,7 @@ ACTIVE_CELL_ID_SECTION_HEADING = "The ID of the active code cell:"
19
19
  ACTIVE_CELL_OUTPUT_SECTION_HEADING = "Output of the active code cell:"
20
20
  GET_CELL_OUTPUT_TOOL_RESPONSE_SECTION_HEADING = "Output of the code cell you just applied the CELL_UPDATE to:"
21
21
  JUPYTER_NOTEBOOK_SECTION_HEADING = "Jupyter Notebook:"
22
+ STREAMLIT_APP_STATUS_SECTION_HEADING = "Streamlit App Status:"
22
23
 
23
24
  # Placeholder text used when trimming content from messages
24
25
  CONTENT_REMOVED_PLACEHOLDER = "Content removed to save space"
@@ -125,15 +126,33 @@ If the user has requested data that you believe is stored in the database:
125
126
  connections[connection_name]["username"]
126
127
  ```
127
128
 
129
+ - The user may colloquially ask for a "list of x", always assume they want a pandas DataFrame.
130
+ - When working with dataframes created from an SQL query, ALWAYS use lowercase column names.
131
+ - If you think the requested data is stored in the database, but you are unsure, then ask the user for clarification.
132
+
133
+ ## Additional MSSQL Rules
134
+
135
+ - When connecting to a Microsoft SQL Server (MSSQL) database, use the following format:
136
+
137
+ ```
138
+ import urllib.parse
139
+
140
+ encoded_password = urllib.parse.quote_plus(password)
141
+ conn_str = f"mssql+pyodbc://username:encoded_password@host:port/database?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes"
142
+ ```
143
+
144
+ - Always URL-encode passwords for MSSQL connections to handle special characters properly.
145
+ - Include the port number in MSSQL connection strings.
146
+ - Use "ODBC+Driver+18+for+SQL+Server" (with plus signs) in the driver parameter.
147
+ - Always include "TrustServerCertificate=yes" for MSSQL connections to avoid SSL certificate issues.
148
+
149
+ ## Additional Oracle Rules
150
+
128
151
  - When connecting to an Oracle database, use the following format:
129
152
  ```
130
153
  conn_str = f"oracle+oracledb://username:password@host:port?service_name=service_name"
131
154
  ```
132
155
 
133
- - The user may colloquially ask for a "list of x", always assume they want a pandas DataFrame.
134
- - When working with dataframes created from an SQL query, ALWAYS use lowercase column names.
135
- - If you think the requested data is stored in the database, but you are unsure, then ask the user for clarification.
136
-
137
156
  Here is the schema:
138
157
  {schemas}
139
158
  """
@@ -1,22 +1,84 @@
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
- from typing import List, Optional
4
+ from typing import List, Optional, Dict
5
5
  from mito_ai.rules.utils import get_rule
6
6
 
7
- def get_rules_str(selected_rules: Optional[List[str]]) -> str:
7
+
8
+ def get_rules_str(additional_context: Optional[List[Dict[str, str]]]) -> str:
8
9
  """
9
- Get a string of the rules that the user has selected.
10
+ Extract the rules from the additional context array, and retrieve the rule content.
10
11
  """
11
- if selected_rules is None:
12
- return ''
13
-
14
- rules_str = ''
12
+ if not additional_context:
13
+ return ""
14
+
15
+ selected_rules = [context["value"] for context in additional_context if context.get("type") == "rule"]
16
+ if len(selected_rules) == 0:
17
+ return ""
18
+
19
+ rules_str = ""
15
20
  for rule in selected_rules:
16
21
  rule_content = get_rule(rule)
17
- if rule_content is None or rule_content == '':
22
+ if rule_content is None or rule_content == "":
18
23
  continue
19
-
24
+
20
25
  rules_str += f"===========\n\nCustom Instructions Provided by User: {rule}\n\n{rule_content}\n\n==========="
21
-
26
+
22
27
  return rules_str
28
+
29
+
30
+ def get_selected_context_str(additional_context: Optional[List[Dict[str, str]]]) -> str:
31
+ """
32
+ Get the selected context from the additional context array.
33
+ """
34
+ if not additional_context:
35
+ return ""
36
+
37
+ # STEP 1: Extract each context type into a separate list
38
+ selected_variables = [context["value"] for context in additional_context if context.get("type") == "variable"]
39
+ selected_files = [context["value"] for context in additional_context if context.get("type") == "file"]
40
+ selected_db_connections = [context["value"] for context in additional_context if context.get("type") == "db"]
41
+ selected_images = [context["value"] for context in additional_context if context.get("type", "").startswith("image/")]
42
+
43
+ # STEP 2: Create a list of strings (instructions) for each context type
44
+ context_parts = []
45
+
46
+ if len(selected_variables) > 0:
47
+ context_parts.append(
48
+ "The following variables have been selected by the user to be used in the task:\n"
49
+ + "\n".join(selected_variables)
50
+ )
51
+
52
+ if len(selected_files) > 0:
53
+ context_parts.append(
54
+ "The following files have been selected by the user to be used in the task:\n"
55
+ + "\n".join(selected_files)
56
+ )
57
+
58
+ if len(selected_db_connections) > 0:
59
+ context_parts.append(
60
+ "The following database connections have been selected by the user to be used in the task:\n"
61
+ + "\n".join(selected_db_connections)
62
+ )
63
+
64
+ if len(selected_images) > 0:
65
+ context_parts.append(
66
+ "The following images have been selected by the user to be used in the task:\n"
67
+ + "\n".join(selected_images)
68
+ )
69
+
70
+ # STEP 3: Combine into a single string
71
+ return "\n\n".join(context_parts)
72
+
73
+
74
+ def get_streamlit_app_status_str(notebook_id: str, notebook_path: str) -> str:
75
+ """
76
+ Get the streamlit app status string.
77
+ """
78
+ from mito_ai.path_utils import does_notebook_id_have_corresponding_app
79
+ if does_notebook_id_have_corresponding_app(notebook_id, notebook_path):
80
+ return "The notebook has an existing Streamlit app that you can edit"
81
+ return "The notebook does not have an existing Streamlit app. If you want to show an app to the user, you must create a new one."
82
+
83
+
84
+