mito-ai 0.1.55__py3-none-any.whl → 0.1.57__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 (79) hide show
  1. mito_ai/__init__.py +2 -0
  2. mito_ai/_version.py +1 -1
  3. mito_ai/anthropic_client.py +7 -6
  4. mito_ai/chart_wizard/__init__.py +3 -0
  5. mito_ai/chart_wizard/handlers.py +52 -0
  6. mito_ai/chart_wizard/urls.py +23 -0
  7. mito_ai/completions/completion_handlers/completion_handler.py +11 -2
  8. mito_ai/completions/completion_handlers/scratchpad_result_handler.py +66 -0
  9. mito_ai/completions/handlers.py +5 -0
  10. mito_ai/completions/models.py +24 -3
  11. mito_ai/completions/prompt_builders/agent_execution_prompt.py +18 -50
  12. mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +82 -95
  13. mito_ai/completions/prompt_builders/agent_system_message.py +304 -276
  14. mito_ai/completions/prompt_builders/chart_conversion_prompt.py +27 -0
  15. mito_ai/completions/prompt_builders/chat_prompt.py +15 -100
  16. mito_ai/completions/prompt_builders/chat_system_message.py +98 -72
  17. mito_ai/completions/prompt_builders/explain_code_prompt.py +22 -24
  18. mito_ai/completions/prompt_builders/inline_completer_prompt.py +78 -107
  19. mito_ai/completions/prompt_builders/prompt_constants.py +35 -45
  20. mito_ai/completions/prompt_builders/prompt_section_registry/__init__.py +70 -0
  21. mito_ai/completions/prompt_builders/prompt_section_registry/active_cell_code.py +15 -0
  22. mito_ai/completions/prompt_builders/prompt_section_registry/active_cell_id.py +10 -0
  23. mito_ai/completions/prompt_builders/prompt_section_registry/active_cell_output.py +20 -0
  24. mito_ai/completions/prompt_builders/prompt_section_registry/base.py +37 -0
  25. mito_ai/completions/prompt_builders/prompt_section_registry/error_traceback.py +17 -0
  26. mito_ai/completions/prompt_builders/prompt_section_registry/example.py +19 -0
  27. mito_ai/completions/prompt_builders/prompt_section_registry/files.py +17 -0
  28. mito_ai/completions/prompt_builders/prompt_section_registry/generic.py +15 -0
  29. mito_ai/completions/prompt_builders/prompt_section_registry/get_cell_output_tool_response.py +21 -0
  30. mito_ai/completions/prompt_builders/prompt_section_registry/notebook.py +19 -0
  31. mito_ai/completions/prompt_builders/prompt_section_registry/rules.py +39 -0
  32. mito_ai/completions/prompt_builders/{utils.py → prompt_section_registry/selected_context.py} +51 -42
  33. mito_ai/completions/prompt_builders/prompt_section_registry/streamlit_app_status.py +25 -0
  34. mito_ai/completions/prompt_builders/prompt_section_registry/task.py +12 -0
  35. mito_ai/completions/prompt_builders/prompt_section_registry/variables.py +18 -0
  36. mito_ai/completions/prompt_builders/scratchpad_result_prompt.py +17 -0
  37. mito_ai/completions/prompt_builders/smart_debug_prompt.py +48 -63
  38. mito_ai/constants.py +0 -3
  39. mito_ai/tests/completions/test_prompt_section_registry.py +44 -0
  40. mito_ai/tests/message_history/test_message_history_utils.py +273 -340
  41. mito_ai/tests/providers/test_anthropic_client.py +7 -3
  42. mito_ai/utils/message_history_utils.py +68 -44
  43. mito_ai/utils/provider_utils.py +8 -1
  44. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +102 -102
  45. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/package.json +2 -2
  46. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +1 -1
  47. mito_ai-0.1.55.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.49c79c62671528877c61.js → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.9d26322f3e78beb2b666.js +2778 -297
  48. mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.9d26322f3e78beb2b666.js.map +1 -0
  49. mito_ai-0.1.55.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.9dfbffc3592eb6f0aef9.js → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.79c1ea8a3cda73a4cb6f.js +17 -17
  50. mito_ai-0.1.55.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.9dfbffc3592eb6f0aef9.js.map → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.79c1ea8a3cda73a4cb6f.js.map +1 -1
  51. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/themes/mito_ai/index.css +7 -2
  52. {mito_ai-0.1.55.dist-info → mito_ai-0.1.57.dist-info}/METADATA +5 -1
  53. {mito_ai-0.1.55.dist-info → mito_ai-0.1.57.dist-info}/RECORD +78 -56
  54. mito_ai-0.1.55.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.49c79c62671528877c61.js.map +0 -1
  55. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
  56. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +0 -0
  57. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +0 -0
  58. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +0 -0
  59. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
  60. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.f5d476ac514294615881.js +0 -0
  61. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.f5d476ac514294615881.js.map +0 -0
  62. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  63. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  64. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  65. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  66. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +0 -0
  67. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +0 -0
  68. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +0 -0
  69. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +0 -0
  70. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  71. {mito_ai-0.1.55.data → mito_ai-0.1.57.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
  72. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +0 -0
  73. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +0 -0
  74. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +0 -0
  75. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +0 -0
  76. {mito_ai-0.1.55.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/themes/mito_ai/index.js +0 -0
  77. {mito_ai-0.1.55.dist-info → mito_ai-0.1.57.dist-info}/WHEEL +0 -0
  78. {mito_ai-0.1.55.dist-info → mito_ai-0.1.57.dist-info}/entry_points.txt +0 -0
  79. {mito_ai-0.1.55.dist-info → mito_ai-0.1.57.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,27 @@
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.completions.prompt_builders.prompt_section_registry import SG, Prompt
6
+ from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
7
+ from mito_ai.completions.prompt_builders.prompt_constants import CHART_CONFIG_RULES
8
+
9
+ def create_chart_conversion_prompt(code: str) -> str:
10
+ """
11
+ Create a prompt for converting matplotlib chart code to be used with the Chart Wizard.
12
+
13
+ Args:
14
+ code: The matplotlib chart code to convert
15
+
16
+ Returns:
17
+ A formatted prompt string
18
+ """
19
+ sections: List[PromptSection] = []
20
+
21
+ sections.append(SG.Generic("Instructions", "The following code contains a matplotlib chart. However, the chart must be converted to a specific format for use in our tool. Below you will find the rules used to create an acceptable chart; use these rules to reformat the code."))
22
+
23
+ sections.append(SG.Generic("Chart Config Rules", CHART_CONFIG_RULES))
24
+ sections.append(SG.Generic("Code to Convert", f"```python\n{code}\n```"))
25
+
26
+ prompt = Prompt(sections)
27
+ return str(prompt)
@@ -2,18 +2,8 @@
2
2
  # Distributed under the terms of the GNU Affero General Public License v3.0 License.
3
3
 
4
4
  from typing import List, Optional, Dict
5
- from mito_ai.completions.prompt_builders.prompt_constants import (
6
- ACTIVE_CELL_ID_SECTION_HEADING,
7
- CHAT_CODE_FORMATTING_RULES,
8
- FILES_SECTION_HEADING,
9
- VARIABLES_SECTION_HEADING,
10
- CODE_SECTION_HEADING,
11
- get_active_cell_output_str,
12
- )
13
- from mito_ai.completions.prompt_builders.utils import (
14
- get_rules_str,
15
- get_selected_context_str,
16
- )
5
+ from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
6
+ from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
17
7
 
18
8
 
19
9
  def create_chat_prompt(
@@ -25,92 +15,17 @@ def create_chat_prompt(
25
15
  input: str,
26
16
  additional_context: Optional[List[Dict[str, str]]] = None,
27
17
  ) -> str:
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
-
33
- prompt = f"""{rules_str}
18
+ sections: List[PromptSection] = [
19
+ SG.Rules(additional_context),
20
+ SG.Generic("Instructions", "Help me complete the following task. I will provide you with a set of variables, existing code, and a task to complete."),
21
+ SG.Files(files),
22
+ SG.Variables(variables),
23
+ SG.SelectedContext(additional_context),
24
+ SG.ActiveCellId(active_cell_id),
25
+ SG.ActiveCellCode(active_cell_code),
26
+ SG.ActiveCellOutput(has_active_cell_output),
27
+ SG.Task(input),
28
+ ]
34
29
 
35
- Help me complete the following task. I will provide you with a set of variables, existing code, and a task to complete.
36
-
37
- {CHAT_CODE_FORMATTING_RULES}
38
-
39
- <Example 1>
40
-
41
- {FILES_SECTION_HEADING}
42
- file_name: sales.csv
43
-
44
- {VARIABLES_SECTION_HEADING}
45
- {{
46
- 'loan_multiplier': 1.5,
47
- 'sales_df': pd.DataFrame({{
48
- 'transaction_date': ['2024-01-02', '2024-01-02', '2024-01-02', '2024-01-02', '2024-01-03'],
49
- 'price_per_unit': [10, 9.99, 13.99, 21.00, 100],
50
- 'units_sold': [1, 2, 1, 4, 5],
51
- 'total_price': [10, 19.98, 13.99, 84.00, 500]
52
- }})
53
- }}
54
-
55
- {ACTIVE_CELL_ID_SECTION_HEADING}
56
- '9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8'
57
-
58
- {CODE_SECTION_HEADING}
59
- ```python
60
- import pandas as pd
61
- sales_df = pd.read_csv('./sales.csv')
62
- ```
63
-
64
- Your task: convert the transaction_date column to datetime and then multiply the total_price column by the sales_multiplier.
65
-
66
- Output:
67
- ```python
68
- import pandas as pd
69
- sales_df = pd.read_csv('./sales.csv')
70
- sales_df['transaction_date'] = pd.to_datetime(sales_df['transaction_date'])
71
- sales_df['total_price'] = sales_df['total_price'] * sales_multiplier
72
- ```
73
-
74
- Applied datetime conversion to enable temporal analysis[MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:2] and revenue adjustment using the 1.5x sales multiplier[MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:3], scaling total revenue from $627.97 to $941.96.
75
-
76
- </Example 1>
77
-
78
- <Example 2>
79
-
80
- {ACTIVE_CELL_ID_SECTION_HEADING}
81
- '1a2b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6'
82
-
83
- {CODE_SECTION_HEADING}
84
- ```python
85
- ```
86
-
87
- Your task: Hello
88
-
89
- Output:
90
- Hey there! I'm Mito AI. How can I help you today?
91
-
92
- </Example 2>
93
-
94
-
95
- {FILES_SECTION_HEADING}
96
- {files_str}
97
-
98
- {VARIABLES_SECTION_HEADING}
99
- {variables_str}
100
-
101
- {ACTIVE_CELL_ID_SECTION_HEADING}
102
- {active_cell_id}
103
-
104
- {CODE_SECTION_HEADING}
105
- ```python
106
- {active_cell_code}
107
- ```
108
-
109
- {selected_context_str}
110
-
111
- {get_active_cell_output_str(has_active_cell_output)}
112
-
113
- Your task: {input}
114
- """
115
-
116
- return prompt
30
+ prompt = Prompt(sections)
31
+ return str(prompt)
@@ -1,17 +1,22 @@
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
5
+ from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
4
6
  from mito_ai.completions.prompt_builders.prompt_constants import (
7
+ CHART_CONFIG_RULES,
5
8
  CHAT_CODE_FORMATTING_RULES,
6
9
  CITATION_RULES,
7
10
  CELL_REFERENCE_RULES,
8
- ACTIVE_CELL_ID_SECTION_HEADING,
9
- CODE_SECTION_HEADING,
10
11
  get_database_rules
11
12
  )
13
+ from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
12
14
 
13
15
  def create_chat_system_message_prompt() -> str:
14
- return f"""You are Mito Data Copilot, an AI assistant for Jupyter. You're a great python programmer, a seasoned data scientist and a subject matter expert.
16
+ sections: List[PromptSection] = []
17
+
18
+ # Add intro text
19
+ sections.append(SG.Generic("Instructions", """You are Mito Data Copilot, an AI assistant for Jupyter. You're a great python programmer, a seasoned data scientist and a subject matter expert.
15
20
 
16
21
  The user is going to ask you for help writing code, debugging code, explaining code, or drawing conclusions from their data/graphs. It is your job to help them accomplish their goal.
17
22
 
@@ -25,77 +30,96 @@ There are three possible types of responses you might give:
25
30
  Other useful information:
26
31
  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.
27
32
  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.
28
-
29
- ====
30
- {CITATION_RULES}
31
-
32
- ====
33
- {CELL_REFERENCE_RULES}
34
-
35
- <Example 1>
36
- {ACTIVE_CELL_ID_SECTION_HEADING}
37
- '7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2'
38
-
39
- {CODE_SECTION_HEADING}
40
- ```python
41
- sales_df = pd.read_csv('sales_data.csv')
42
- monthly_revenue = sales_df.groupby('month')['revenue'].sum()
43
- top_month = monthly_revenue.idxmax()
44
- peak_revenue = monthly_revenue.max()
45
- growth_rate = (monthly_revenue.iloc[-1] / monthly_revenue.iloc[0] - 1) * 100
46
- ```
47
-
48
- Your task: What are the key revenue insights from this sales data?
49
-
50
- Output:
51
- Peak monthly revenue reached $847,392 in March[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:2-3], representing a 23.8% year-over-year growth rate[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:4]. The revenue aggregation analysis[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:1-2] reveals strong seasonal performance patterns.
52
-
53
- </Example 1>
54
-
55
- Notice in the example above:
56
- - Citations support specific facts and numbers, not vague summaries
57
- - Single line citations reference specific calculations (e.g., :4 for growth rate)
58
- - Multiline citations reference broader analysis blocks (e.g., :1-2 for the groupby operation)
59
- - Language is information-dense with concrete metrics
60
- - All line numbers are 0-indexed
61
-
62
- <Example 2>
63
-
64
- {ACTIVE_CELL_ID_SECTION_HEADING}
65
- '1a2b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6'
66
-
67
- {CODE_SECTION_HEADING}
68
- ```python
69
- ```
70
-
71
- Your task: Hello
72
-
73
- Output:
74
- Hey there! I'm Mito AI. How can I help you today?
75
-
76
- </Example 2>
77
-
78
- Notice in the example above that the user is just sending a friendly message, so we respond with a friendly message and do not return any code.
79
-
80
- ===
81
- {get_database_rules()}
82
-
83
- ====
84
- {CHAT_CODE_FORMATTING_RULES}
85
-
86
- ====
87
-
88
- CODE STYLE
89
-
33
+ """))
34
+
35
+ sections.append(SG.Generic("Chart Config Rules", CHART_CONFIG_RULES))
36
+ sections.append(SG.Generic("DatabaseRules", get_database_rules()))
37
+ sections.append(SG.Generic("Citation Rules", CITATION_RULES))
38
+ sections.append(SG.Generic("Cell Reference Rules", CELL_REFERENCE_RULES))
39
+
40
+ # Example 1
41
+ sections.append(SG.Example("Example 1", f"""
42
+
43
+ Notice in this example:
44
+ - Citations support specific facts and numbers, not vague summaries
45
+ - Single line citations reference specific calculations (e.g., :4 for growth rate)
46
+ - Multiline citations reference broader analysis blocks (e.g., :1-2 for the groupby operation)
47
+ - Language is information-dense with concrete metrics
48
+ - All line numbers are 0-indexed
49
+
50
+ Active Cell ID: '7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2'
51
+
52
+ Active Cell Code:
53
+ ```python
54
+ sales_df = pd.read_csv('sales_data.csv')\nmonthly_revenue = sales_df.groupby('month')['revenue'].sum()\ntop_month = monthly_revenue.idxmax()\npeak_revenue = monthly_revenue.max()\ngrowth_rate = (monthly_revenue.iloc[-1] / monthly_revenue.iloc[0] - 1) * 100
55
+ ```
56
+
57
+ Your Task: What are the key revenue insights from this sales data?
58
+
59
+ Output:
60
+ Peak monthly revenue reached $847,392 in March[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:2-3], representing a 23.8% year-over-year growth rate[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:4]. The revenue aggregation analysis[MITO_CITATION:7b3a9e2c-5d14-4c83-b2f9-d67891e4a5f2:1-2] reveals strong seasonal performance patterns."""))
61
+
62
+ sections.append(SG.Example("Example 2", """
63
+
64
+ Notice in this example that the user is just sending a friendly message, so we respond with a friendly message and do not return any code.
65
+
66
+ Active Cell ID:
67
+ '1a2b3c4d-5e6f-7g8h-9i0j-k1l2m3n4o5p6'
68
+
69
+ Active Cell Code:
70
+ ```python
71
+ ```
72
+
73
+ Your task: Hello
74
+
75
+ Output:
76
+ Hey there! I'm Mito AI. How can I help you today?"""))
77
+
78
+
79
+ sections.append(SG.Example("Example 3", """
80
+ Files:
81
+ "file_name: sales.csv"
82
+
83
+ Variables:
84
+ {{
85
+ 'loan_multiplier': 1.5,
86
+ 'sales_df': pd.DataFrame({
87
+ 'transaction_date': ['2024-01-02', '2024-01-02', '2024-01-02', '2024-01-02', '2024-01-03'],
88
+ 'price_per_unit': [10, 9.99, 13.99, 21.00, 100],
89
+ 'units_sold': [1, 2, 1, 4, 5],
90
+ 'total_price': [10, 19.98, 13.99, 84.00, 500]
91
+ })
92
+ }}
93
+
94
+ Active Cell ID: '9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8'
95
+
96
+ Active Cell Code: import pandas as pd\nsales_df = pd.read_csv('./sales.csv')
97
+
98
+ Your Task: convert the transaction_date column to datetime and then multiply the total_price column by the sales_multiplier.
99
+
100
+ Output:
101
+ ```python
102
+ import pandas as pd
103
+ sales_df = pd.read_csv('./sales.csv')
104
+ sales_df['transaction_date'] = pd.to_datetime(sales_df['transaction_date'])
105
+ sales_df['total_price'] = sales_df['total_price'] * sales_multiplier
106
+ ```
107
+
108
+ Applied datetime conversion to enable temporal analysis[MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:2] and revenue adjustment using the 1.5x sales multiplier[MITO_CITATION:9c0d5fda-2b16-4f52-a1c5-a48892f3e2e8:3], scaling total revenue from $627.97 to $941.96."""))
109
+
110
+ # Add code formatting rules
111
+ sections.append(SG.Generic("CODE FORMATTING RULES", CHAT_CODE_FORMATTING_RULES))
112
+
113
+ # Add code style
114
+ sections.append(SG.Generic("CODE STYLE", """
90
115
  - Avoid using try/except blocks and other defensive programming patterns (like checking if files exist before reading them, verifying variables are defined before using them, etc.) unless there is a really good reason. In Jupyter notebooks, errors should surface immediately so users can identify and fix issues. When errors are caught and suppressed or when defensive checks hide problems, users continue running broken code without realizing it, and the agent's auto-error-fix loop cannot trigger. If a column doesn't exist, a file is missing, a variable isn't defined, or a module isn't installed, let it error. The user needs to know.
91
116
  - Write code that preserves the intent of the original code shared with you and the task to complete.
92
117
  - Make the solution as simple as possible.
93
118
  - Do not add temporary comments like '# Fixed the typo here' or '# Added this line to fix the error'
94
- - When importing matplotlib, write the code `%matplotlib inline` to make sure the graphs render in Jupyter.
95
-
96
- ====
97
-
98
- IMPORTANT RULES:
119
+ - When importing matplotlib, write the code `%matplotlib inline` to make sure the graphs render in Jupyter."""))
120
+
121
+ # Add important rules
122
+ sections.append(SG.Generic("IMPORTANT RULES", """
99
123
  - Do not recreate variables that already exist
100
124
  - Keep as much of the original code as possible
101
125
  - When updating an existing code cell, return the full code cell with the update applied. Do not only return part of the code cell with a comment like "# Updated code starts here", etc.
@@ -103,5 +127,7 @@ IMPORTANT RULES:
103
127
  - Write code that preserves the intent of the original code shared with you and the task to complete.
104
128
  - Make the solution as simple as possible.
105
129
  - Reuse as much of the existing code as possible.
106
- - Whenever writing Python code, it should be a python code block starting with ```python and ending with ```
107
- """
130
+ - Whenever writing Python code, it should be a python code block starting with ```python and ending with ```"""))
131
+
132
+ prompt = Prompt(sections)
133
+ return str(prompt)
@@ -1,32 +1,30 @@
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 mito_ai.completions.prompt_builders.prompt_constants import CODE_SECTION_HEADING
4
+ from typing import List
5
+ from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
6
+ from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
5
7
 
6
- def create_explain_code_prompt(active_cell_code: str) -> str:
7
- prompt = f"""Explain the code in the active code cell to me like I have a basic understanding of Python. Don't explain each line, but instead explain the overall logic of the code.
8
-
9
- <Example>
10
8
 
11
- {CODE_SECTION_HEADING}
12
-
13
- ```python
14
- def multiply(x, y):
15
- return x * y
16
- ```
9
+ def create_explain_code_prompt(active_cell_code: str) -> str:
10
+ sections: List[PromptSection] = []
11
+ # Add intro text
12
+ sections.append(SG.Generic("Instructions", "Explain the code in the active code cell to me like I have a basic understanding of Python. Don't explain each line, but instead explain the overall logic of the code."))
13
+
14
+ # Add example
15
+ example_content = f"""{SG.ActiveCellCode('''def multiply(x, y):
16
+ return x * y''')}
17
17
 
18
18
  Output:
19
19
 
20
- This code creates a function called `multiply` that takes two arguments `x` and `y`, and returns the product of `x` and `y`.
21
-
22
- </Example>
23
-
24
- {CODE_SECTION_HEADING}
25
-
26
- ```python
27
- {active_cell_code}
28
- ```
29
-
30
- Output:
31
- """
32
- return prompt
20
+ This code creates a function called `multiply` that takes two arguments `x` and `y`, and returns the product of `x` and `y`."""
21
+ sections.append(SG.Example("Example", example_content))
22
+
23
+ # Add actual code section
24
+ sections.append(SG.ActiveCellCode(active_cell_code))
25
+
26
+ # Add output prompt
27
+ sections.append(SG.Task("Output:"))
28
+
29
+ prompt = Prompt(sections)
30
+ return str(prompt)
@@ -2,11 +2,8 @@
2
2
  # Distributed under the terms of the GNU Affero General Public License v3.0 License.
3
3
 
4
4
  from typing import List
5
- from mito_ai.completions.prompt_builders.prompt_constants import (
6
- FILES_SECTION_HEADING,
7
- VARIABLES_SECTION_HEADING,
8
- CODE_SECTION_HEADING
9
- )
5
+ from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
6
+ from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
10
7
 
11
8
 
12
9
  def create_inline_prompt(
@@ -15,10 +12,10 @@ def create_inline_prompt(
15
12
  variables: List[str],
16
13
  files: List[str]
17
14
  ) -> str:
18
- variables_str = '\n'.join([f"{variable}" for variable in variables])
19
- files_str = '\n'.join([f"file_name: {file}" for file in files])
15
+ sections: List[PromptSection] = []
20
16
 
21
- prompt = f"""You are a coding assistant that lives inside of JupyterLab. Your job is to help the user write code.
17
+ # Add intro text
18
+ sections.append(SG.Task("""You are a coding assistant that lives inside of JupyterLab. Your job is to help the user write code.
22
19
 
23
20
  You're given the current code cell, the user's cursor position, and the variables defined in the notebook. The user's cursor is signified by the symbol <cursor>.
24
21
 
@@ -27,28 +24,30 @@ CRITICAL FORMATTING RULES:
27
24
  2. If you are finishing a line of code that the user started, return the full line of code with no newline character at the start or end.
28
25
  3. Your response must preserve correct Python indentation and spacing. For example, if you're completing a line of indented code, you must preserve the indentation.
29
26
 
30
- Your job is to complete the code that matches the user's intent. Write the minimal code to achieve the user's intent. Don't expand upon the user's intent.
31
-
32
- <Example 1>
33
- {FILES_SECTION_HEADING}
34
- file_name: sales.csv
27
+ Your job is to complete the code that matches the user's intent. Write the minimal code to achieve the user's intent. Don't expand upon the user's intent."""))
28
+
29
+ # Example 1
30
+ example1_content = f"""
31
+ Files:
32
+ "file_name: sales.csv"
35
33
 
36
- {VARIABLES_SECTION_HEADING}
34
+ Variables:
37
35
  {{
38
36
  'loan_multiplier': 1.5,
39
- 'sales_df': pd.DataFrame({{
37
+ 'sales_df': pd.DataFrame({
40
38
  'transaction_date': ['2024-01-02', '2024-01-02', '2024-01-02', '2024-01-02', '2024-01-03'],
41
39
  'price_per_unit': [10, 9.99, 13.99, 21.00, 100],
42
40
  'units_sold': [1, 2, 1, 4, 5],
43
41
  'total_price': [10, 19.98, 13.99, 84.00, 500]
44
- }})
42
+ })
45
43
  }}
46
44
 
47
- {CODE_SECTION_HEADING}
45
+ Active Cell Code:
48
46
  ```python
49
47
  import pandas as pd
50
48
  sales_df = pd.read_csv('./sales.csv')
51
49
 
50
+
52
51
  # Multiply the total_price column by the loan_multiplier<cursor>
53
52
  ```
54
53
 
@@ -57,23 +56,22 @@ Output:
57
56
 
58
57
  sales_df['total_price'] = sales_df['total_price'] * loan_multiplier
59
58
  ```
60
- </Example 1>
61
59
 
62
- IMPORTANT: Notice in Example 1 that the output starts with a newline because the cursor was at the end of a comment. This newline is REQUIRED to maintain proper Python formatting.
63
-
64
- <Example 2>
65
- {FILES_SECTION_HEADING}
60
+ Notice in Example 1 that the output starts with a newline because the cursor was at the end of a comment. This newline is REQUIRED to maintain proper Python formatting."""
66
61
 
62
+ sections.append(SG.Example("Example 1", example1_content))
63
+
64
+ # Example 2
65
+ example2_content = """
66
+ Files:
67
67
 
68
- {VARIABLES_SECTION_HEADING}
69
- {{
70
- df: pd.DataFrame({{
71
- 'age': [20, 25, 22, 23, 29],
72
- 'name': ['Nawaz', 'Aaron', 'Charlie', 'Tamir', 'Eve'],
73
- }})
74
- }}
68
+ Variables:
69
+ df: pd.DataFrame({
70
+ 'age': [20, 25, 22, 23, 29],
71
+ 'name': ['Nawaz', 'Aaron', 'Charlie', 'Tamir', 'Eve'],
72
+ })
75
73
 
76
- {CODE_SECTION_HEADING}
74
+ Active Cell Code:
77
75
  ```python
78
76
  df['age'] = df[<cursor>['age'] > 23]
79
77
  ```
@@ -82,18 +80,20 @@ Output:
82
80
  ```python
83
81
  df['age'] = df[df['age'] > 23]
84
82
  ```
85
- </Example 2>
86
-
87
- IMPORTANT: Notice in Example 2 that the output does NOT start with a newline because the cursor is in the middle of existing code.
88
83
 
89
- <Example 3>
90
- {FILES_SECTION_HEADING}
91
- file_name: voters.csv
84
+ IMPORTANT: Notice in Example 2 that the output does NOT start with a newline because the cursor is in the middle of existing code."
85
+ """
86
+ sections.append(SG.Example("Example 2", example2_content))
87
+
88
+ # Example 3
89
+ example3_content = f"""
90
+ Files:
91
+ "file_name: voters.csv"
92
92
 
93
- {VARIABLES_SECTION_HEADING}
93
+ Variables:
94
94
  {{}}
95
95
 
96
- {CODE_SECTION_HEADING}
96
+ Active Cell Code:
97
97
  ```python
98
98
  voters = pd.read_csv('./voters.csv')
99
99
 
@@ -108,90 +108,61 @@ ohio_voters = voters[voters['state'] == 'OH']
108
108
  ca_voters = voters[voters['state'] == 'CA']
109
109
  tx_voters = voters[voters['state'] == 'TX']
110
110
  ```
111
- </Example 3>
112
-
113
- IMPORTANT: Notice in Example 3 that output does not start with a newline character because it wasnts to continue the line of code that the user started. Also notice the output contains three lines of code because that is the minimal code to achieve the user's intent.
114
111
 
115
- <Example 4>
116
- {FILES_SECTION_HEADING}
117
- file_name: july_2025.xlsx
118
- file_name: august_2025.xlsx
112
+ IMPORTANT: Notice in Example 3 that output does not start with a newline character because it wasnts to continue the line of code that the user started. Also notice the output contains three lines of code because that is the minimal code to achieve the user's intent."""
113
+ sections.append(SG.Example("Example 3", example3_content))
114
+
115
+ # Example 4
116
+ example4_content = f"""
117
+ Files:
118
+ "file_name: july_2025.xlsx"
119
+ "file_name: august_2025.xlsx"
119
120
 
120
- {VARIABLES_SECTION_HEADING}
121
+ Variables:
121
122
  {{}}
122
123
 
123
- {CODE_SECTION_HEADING}
124
+ Active Cell Code:
124
125
  ```python
125
- # Display the first 5 rows of the dataframe
126
- df.head()
127
- <cursor>
128
- ```
129
-
130
- Output:
131
- ```python
132
- ```
133
- </Example 4>
134
-
135
- IMPORTANT: Notice in Example 4 that the output is empty becuase the user's intent is already complete.
136
-
137
- <Example 5>
138
- {FILES_SECTION_HEADING}
139
-
140
-
141
- {VARIABLES_SECTION_HEADING}
126
+ ```"""
127
+ sections.append(SG.Example("Example 4", example4_content))
128
+
129
+ # Example 5
130
+ example5_content = f"""
131
+ Files:
142
132
  {{}}
143
133
 
144
- {CODE_SECTION_HEADING}
134
+ Active Cell Code:
145
135
  ```python
146
- def even_and_odd():
147
- for i in range(10):
148
- if i % 2 == 0:
149
- print(f"Even: {{i}}")
150
- else:
151
- pri<cursor>
136
+ def even_and_odd():\n for i in range(10):\n if i % 2 == 0:\n print(f\"Even: {{i}}\")\n else:\n pri<cursor>
152
137
  ```
153
138
 
154
139
  Output:
155
- ```python
156
- print(f"Odd: {{i}}")
157
- ```
158
- </Example 5>
159
-
160
- IMPORTANT: Notice in Example 5 that the output is indented several times because the code must be executed as part of the else block.
161
-
162
- <Example 6>
163
- {FILES_SECTION_HEADING}
164
-
165
-
166
- {VARIABLES_SECTION_HEADING}
140
+ ```python"""
141
+ sections.append(SG.Example("Example 5", example5_content))
142
+
143
+ # Example 6
144
+ example6_content = f"""
145
+ Files:
167
146
  {{}}
168
147
 
169
- {CODE_SECTION_HEADING}
170
- ```python
171
- days_in_week <cursor>
172
- ```
173
-
174
- Output:
148
+ Active Cell Code:
175
149
  ```python
176
150
  days_in_week = 7
177
151
  ```
178
- </Example 6>
179
-
180
- IMPORTANT: Notice in Example 6 that inorder to finish the variable declaration, the output continues the existing line of code and does not start with a new line character.
181
152
 
182
- Your Task:
183
-
184
- {FILES_SECTION_HEADING}
185
- {files_str}
186
-
187
- {VARIABLES_SECTION_HEADING}
188
- {variables_str}
189
-
190
- {CODE_SECTION_HEADING}
191
- ```python
192
- {prefix}<cursor>{suffix}
193
- ```
153
+ IMPORTANT: Notice in Example 6 that inorder to finish the variable declaration, the output continues the existing line of code and does not start with a new line character."""
154
+ sections.append(SG.Example("Example 6", example6_content))
155
+
156
+ # Add task sections
157
+ sections.append(SG.Task("Your Task:"))
158
+
159
+ sections.append(SG.Files(files))
160
+ sections.append(SG.Variables(variables))
161
+
162
+ code_content = f"{prefix}<cursor>{suffix}\n"
163
+ sections.append(SG.ActiveCellCode(code_content))
164
+
165
+ sections.append(SG.Task("Output:"))
194
166
 
195
- Output:
196
- """
197
- return prompt
167
+ prompt = Prompt(sections)
168
+ return str(prompt)