mito-ai 0.1.46__py3-none-any.whl → 0.1.47__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mito-ai might be problematic. Click here for more details.
- mito_ai/_version.py +1 -1
- mito_ai/app_deploy/handlers.py +97 -77
- mito_ai/app_deploy/models.py +16 -12
- mito_ai/completions/models.py +4 -1
- mito_ai/completions/prompt_builders/agent_execution_prompt.py +6 -1
- mito_ai/completions/prompt_builders/agent_system_message.py +63 -4
- mito_ai/completions/prompt_builders/chat_system_message.py +4 -0
- mito_ai/completions/prompt_builders/prompt_constants.py +1 -0
- mito_ai/completions/prompt_builders/utils.py +14 -0
- mito_ai/path_utils.py +56 -0
- mito_ai/streamlit_conversion/agent_utils.py +4 -201
- mito_ai/streamlit_conversion/prompts/prompt_constants.py +142 -152
- mito_ai/streamlit_conversion/prompts/streamlit_error_correction_prompt.py +3 -3
- mito_ai/streamlit_conversion/prompts/streamlit_finish_todo_prompt.py +2 -2
- mito_ai/streamlit_conversion/prompts/update_existing_app_prompt.py +2 -2
- mito_ai/streamlit_conversion/search_replace_utils.py +93 -0
- mito_ai/streamlit_conversion/streamlit_agent_handler.py +29 -39
- mito_ai/streamlit_conversion/streamlit_utils.py +11 -64
- mito_ai/streamlit_conversion/validate_streamlit_app.py +5 -18
- mito_ai/streamlit_preview/handlers.py +44 -84
- mito_ai/streamlit_preview/manager.py +6 -6
- mito_ai/streamlit_preview/utils.py +16 -19
- mito_ai/tests/streamlit_conversion/test_apply_search_replace.py +226 -0
- mito_ai/tests/streamlit_conversion/test_streamlit_agent_handler.py +29 -53
- mito_ai/tests/streamlit_conversion/test_streamlit_utils.py +26 -29
- mito_ai/tests/streamlit_conversion/test_validate_streamlit_app.py +6 -3
- mito_ai/tests/streamlit_preview/test_streamlit_preview_handler.py +12 -15
- mito_ai/tests/streamlit_preview/test_streamlit_preview_manager.py +22 -26
- mito_ai/user/handlers.py +15 -3
- mito_ai/utils/create.py +17 -1
- mito_ai/utils/error_classes.py +42 -0
- mito_ai/utils/message_history_utils.py +3 -1
- mito_ai/utils/telemetry_utils.py +75 -10
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +1 -1
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/package.json +2 -2
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +1 -1
- mito_ai-0.1.46.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.20f12766ecd3d430568e.js → mito_ai-0.1.47.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.2db61d2b629817845901.js +1274 -293
- mito_ai-0.1.47.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.2db61d2b629817845901.js.map +1 -0
- mito_ai-0.1.46.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.54126ab6511271265443.js → mito_ai-0.1.47.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.e22c6cd4e56c32116daa.js +7 -7
- mito_ai-0.1.46.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.54126ab6511271265443.js.map → mito_ai-0.1.47.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.e22c6cd4e56c32116daa.js.map +1 -1
- {mito_ai-0.1.46.dist-info → mito_ai-0.1.47.dist-info}/METADATA +1 -1
- {mito_ai-0.1.46.dist-info → mito_ai-0.1.47.dist-info}/RECORD +67 -65
- mito_ai/tests/streamlit_conversion/test_apply_patch_to_text.py +0 -368
- mito_ai/tests/streamlit_conversion/test_fix_diff_headers.py +0 -533
- mito_ai-0.1.46.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.20f12766ecd3d430568e.js.map +0 -1
- /mito_ai/streamlit_conversion/{streamlit_system_prompt.py → prompts/streamlit_system_prompt.py} +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.5876024bb17dbd6a3ee6.js.map +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_dist_esm_index_mjs.6bac1a8c4cc93f15f6b7.js.map +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_aws-amplify_ui-react_dist_esm_index_mjs.4fcecd65bef9e9847609.js.map +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.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
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js.map +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js +0 -0
- {mito_ai-0.1.46.data → mito_ai-0.1.47.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_vscode-diff_dist_index_js.ea55f1f9346638aafbcf.js.map +0 -0
- {mito_ai-0.1.46.dist-info → mito_ai-0.1.47.dist-info}/WHEEL +0 -0
- {mito_ai-0.1.46.dist-info → mito_ai-0.1.47.dist-info}/entry_points.txt +0 -0
- {mito_ai-0.1.46.dist-info → mito_ai-0.1.47.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,221 +1,24 @@
|
|
|
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
|
|
4
|
+
from typing import List, Tuple
|
|
5
5
|
import re
|
|
6
6
|
from anthropic.types import MessageParam
|
|
7
|
-
from mito_ai.streamlit_conversion.streamlit_system_prompt import streamlit_system_prompt
|
|
7
|
+
from mito_ai.streamlit_conversion.prompts.streamlit_system_prompt import streamlit_system_prompt
|
|
8
8
|
from mito_ai.utils.anthropic_utils import stream_anthropic_completion_from_mito_server
|
|
9
|
-
from unidiff import PatchSet
|
|
10
9
|
from mito_ai.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER
|
|
11
10
|
from mito_ai.completions.models import MessageType
|
|
12
11
|
|
|
13
|
-
STREAMLIT_AI_MODEL = "claude-
|
|
12
|
+
STREAMLIT_AI_MODEL = "claude-sonnet-4-5-20250929"
|
|
14
13
|
|
|
15
14
|
def extract_todo_placeholders(agent_response: str) -> List[str]:
|
|
16
15
|
"""Extract TODO placeholders from the agent's response"""
|
|
17
16
|
return [line.strip() for line in agent_response.split('\n') if MITO_TODO_PLACEHOLDER in line]
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
def apply_patch_to_text(text: str, diff: str) -> str:
|
|
21
|
-
"""
|
|
22
|
-
Apply a *unified-diff* (git-style) patch to the given text and return
|
|
23
|
-
the updated contents.
|
|
24
|
-
|
|
25
|
-
Parameters
|
|
26
|
-
----------
|
|
27
|
-
text : str
|
|
28
|
-
The original file contents.
|
|
29
|
-
diff : str
|
|
30
|
-
A unified diff that transforms *text* into the desired output.
|
|
31
|
-
The diff must reference exactly one file (the Streamlit app).
|
|
32
|
-
NOTE: This assumes a custom format where BOTH -X,Y and +X,Y
|
|
33
|
-
reference the original file line numbers.
|
|
34
|
-
|
|
35
|
-
Returns
|
|
36
|
-
-------
|
|
37
|
-
str
|
|
38
|
-
The patched contents.
|
|
39
|
-
|
|
40
|
-
Raises
|
|
41
|
-
------
|
|
42
|
-
ValueError
|
|
43
|
-
If the patch cannot be applied or references more than one file.
|
|
44
|
-
"""
|
|
45
|
-
# Nothing to do
|
|
46
|
-
if not diff.strip():
|
|
47
|
-
return text
|
|
48
|
-
|
|
49
|
-
# Parse the patch
|
|
50
|
-
patch = PatchSet(diff.splitlines(keepends=True))
|
|
51
|
-
|
|
52
|
-
# We expect a single-file patch (what the prompt asks the model to emit)
|
|
53
|
-
if len(patch) == 0:
|
|
54
|
-
raise ValueError("No patches found in diff")
|
|
55
|
-
|
|
56
|
-
# Check that all patches are for the same file
|
|
57
|
-
file_names = set(p.source_file for p in patch)
|
|
58
|
-
if len(file_names) > 1:
|
|
59
|
-
raise ValueError(
|
|
60
|
-
f"Expected patches for exactly one file, got files: {file_names}"
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
# Apply all hunks from all patches (they should all be for the same file)
|
|
64
|
-
original_lines = text.splitlines(keepends=True)
|
|
65
|
-
result_lines: List[str] = []
|
|
66
|
-
cursor = 0 # index in original_lines (0-based)
|
|
67
|
-
|
|
68
|
-
# Process all hunks from all patches
|
|
69
|
-
# We only expect one patch file, but it always returns as a list
|
|
70
|
-
# so we just iterate over it
|
|
71
|
-
for file_patch in patch:
|
|
72
|
-
for hunk in file_patch:
|
|
73
|
-
# Since hunks reference the original file, just convert to 0-based
|
|
74
|
-
hunk_start = hunk.source_start - 1
|
|
75
|
-
|
|
76
|
-
# Copy unchanged lines before this hunk
|
|
77
|
-
while cursor < hunk_start:
|
|
78
|
-
if cursor < len(original_lines):
|
|
79
|
-
result_lines.append(original_lines[cursor])
|
|
80
|
-
cursor += 1
|
|
81
|
-
|
|
82
|
-
# Apply hunk line-by-line
|
|
83
|
-
for line in hunk:
|
|
84
|
-
if line.is_context:
|
|
85
|
-
# Use the line from the diff to preserve exact formatting
|
|
86
|
-
result_lines.append(line.value)
|
|
87
|
-
cursor += 1
|
|
88
|
-
elif line.is_removed:
|
|
89
|
-
cursor += 1 # Skip this line from the original
|
|
90
|
-
elif line.is_added:
|
|
91
|
-
# Use the line from the diff to preserve exact formatting
|
|
92
|
-
result_lines.append(line.value)
|
|
93
|
-
|
|
94
|
-
# Copy any remaining lines after the last hunk
|
|
95
|
-
result_lines.extend(original_lines[cursor:])
|
|
96
|
-
|
|
97
|
-
return "".join(result_lines)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def fix_context_lines(diff: str) -> str:
|
|
101
|
-
"""
|
|
102
|
-
Fix context lines in unified diff to ensure they all start with a space character.
|
|
103
|
-
|
|
104
|
-
In unified diffs, context lines (unchanged lines) must start with a single space ' ',
|
|
105
|
-
even if the line itself is empty. The AI sometimes generates diffs where empty
|
|
106
|
-
context lines are just blank lines without the leading space, which causes the
|
|
107
|
-
unidiff parser to fail.
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
diff (str): The unified diff string
|
|
111
|
-
|
|
112
|
-
Returns:
|
|
113
|
-
str: The corrected diff with proper context line formatting
|
|
114
|
-
"""
|
|
115
|
-
lines = diff.split('\n')
|
|
116
|
-
corrected_lines = []
|
|
117
|
-
in_hunk = False
|
|
118
|
-
|
|
119
|
-
for i, line in enumerate(lines):
|
|
120
|
-
# Check if we're entering a hunk
|
|
121
|
-
if line.startswith('@@'):
|
|
122
|
-
in_hunk = True
|
|
123
|
-
corrected_lines.append(line)
|
|
124
|
-
continue
|
|
125
|
-
|
|
126
|
-
# Check if we're leaving a hunk (new file header)
|
|
127
|
-
if line.startswith('---') or line.startswith('+++'):
|
|
128
|
-
in_hunk = False
|
|
129
|
-
corrected_lines.append(line)
|
|
130
|
-
continue
|
|
131
|
-
|
|
132
|
-
if in_hunk:
|
|
133
|
-
# We're inside a hunk
|
|
134
|
-
if line.startswith(' ') or line.startswith('-') or line.startswith('+'):
|
|
135
|
-
# Already has proper diff marker
|
|
136
|
-
corrected_lines.append(line)
|
|
137
|
-
elif line.strip() == '':
|
|
138
|
-
# Empty line should be a context line with leading space
|
|
139
|
-
corrected_lines.append(' ')
|
|
140
|
-
else:
|
|
141
|
-
# Line without diff marker - treat as context line
|
|
142
|
-
corrected_lines.append(' ' + line)
|
|
143
|
-
else:
|
|
144
|
-
# Outside hunk - keep as is
|
|
145
|
-
corrected_lines.append(line)
|
|
146
|
-
|
|
147
|
-
return '\n'.join(corrected_lines)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def fix_diff_headers(diff: str) -> str:
|
|
151
|
-
"""
|
|
152
|
-
The AI is generally not very good at counting the number of lines in the diff. If the hunk header has
|
|
153
|
-
an incorrect count, then the patch will fail. So instead we just calculate the counts ourselves, its deterministic.
|
|
154
|
-
|
|
155
|
-
If no header is provided at all, then there is nothing to fix.
|
|
156
|
-
"""
|
|
157
|
-
# First fix context lines to ensure they have proper leading spaces
|
|
158
|
-
diff = fix_context_lines(diff)
|
|
159
|
-
|
|
160
|
-
lines = diff.split('\n')
|
|
161
|
-
|
|
162
|
-
for i, line in enumerate(lines):
|
|
163
|
-
if line.startswith('@@'):
|
|
164
|
-
# Extract the starting line numbers
|
|
165
|
-
match = re.match(r'@@ -(\d+),\d+ \+(\d+),\d+ @@', line)
|
|
166
|
-
if match:
|
|
167
|
-
old_start = match.group(1)
|
|
168
|
-
new_start = match.group(2)
|
|
169
|
-
|
|
170
|
-
# Count lines in this hunk
|
|
171
|
-
old_count = 0
|
|
172
|
-
new_count = 0
|
|
173
|
-
|
|
174
|
-
# Find the end of this hunk (next @@ line or end of file)
|
|
175
|
-
hunk_end = len(lines)
|
|
176
|
-
for j in range(i + 1, len(lines)):
|
|
177
|
-
if lines[j].startswith('@@'):
|
|
178
|
-
hunk_end = j
|
|
179
|
-
break
|
|
180
|
-
|
|
181
|
-
# Count lines in this hunk
|
|
182
|
-
for j in range(i + 1, hunk_end):
|
|
183
|
-
hunk_line = lines[j]
|
|
184
|
-
# Empty lines are treated as context lines
|
|
185
|
-
if hunk_line == '' or hunk_line.startswith(' ') or hunk_line.startswith('-'):
|
|
186
|
-
old_count += 1
|
|
187
|
-
if hunk_line == '' or hunk_line.startswith(' ') or hunk_line.startswith('+'):
|
|
188
|
-
new_count += 1
|
|
189
|
-
|
|
190
|
-
# Replace the header with correct counts
|
|
191
|
-
lines[i] = f"@@ -{old_start},{old_count} +{new_start},{new_count} @@"
|
|
192
|
-
|
|
193
|
-
corrected_diff = '\n'.join(lines)
|
|
194
|
-
corrected_diff = corrected_diff.lstrip()
|
|
195
|
-
|
|
196
|
-
# If there is no diff, just return it without fixing file headers
|
|
197
|
-
if len(corrected_diff) == 0:
|
|
198
|
-
return corrected_diff
|
|
199
|
-
|
|
200
|
-
# Remove known problametic file component headers that the AI sometimes returns
|
|
201
|
-
problamatic_file_header_components = ['--- a/app.py +++ b/app.py']
|
|
202
|
-
for problamatic_file_header_component in problamatic_file_header_components:
|
|
203
|
-
corrected_diff = corrected_diff.removeprefix(problamatic_file_header_component).lstrip()
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# If the diff is missing the file component of the header, add it
|
|
207
|
-
valid_header_component = """--- a/app.py
|
|
208
|
-
+++ b/app.py"""
|
|
209
|
-
if not corrected_diff.startswith(valid_header_component):
|
|
210
|
-
corrected_diff = valid_header_component + '\n' + corrected_diff
|
|
211
|
-
|
|
212
|
-
return corrected_diff
|
|
213
|
-
|
|
214
|
-
|
|
215
18
|
async def get_response_from_agent(message_to_agent: List[MessageParam]) -> str:
|
|
216
19
|
"""Gets the streaming response from the agent using the mito server"""
|
|
217
20
|
model = STREAMLIT_AI_MODEL
|
|
218
|
-
max_tokens =
|
|
21
|
+
max_tokens = 64000 # TODO: If we move to haiku, we must reset this to 8192
|
|
219
22
|
temperature = 0.2
|
|
220
23
|
|
|
221
24
|
accumulated_response = ""
|
|
@@ -3,121 +3,154 @@
|
|
|
3
3
|
|
|
4
4
|
MITO_TODO_PLACEHOLDER = "# MITO_TODO_PLACEHOLDER"
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
RESPONSE FORMAT:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
+ {{'id': 1, 'name': 'New'}},
|
|
72
|
-
+ {{'id': 2, 'name': 'Also New'}},
|
|
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
|
|
73
71
|
```
|
|
74
72
|
</Example 1>
|
|
75
73
|
|
|
76
|
-
<Example 2:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
import os
|
|
87
|
-
+import sys
|
|
88
|
-
@@ -30,1 +30,1 @@
|
|
89
|
-
-def process():
|
|
90
|
-
+def process_data():
|
|
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
|
|
91
84
|
```
|
|
92
85
|
</Example 2>
|
|
93
86
|
|
|
94
|
-
<Example 3:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@@ -57,1 +57,1 @@
|
|
102
|
-
data_list = [
|
|
103
|
-
{{'id': 1, 'name': 'Item A', 'category': 'Type 1', 'value': 100}},
|
|
104
|
-
{{'id': 2, 'name': 'Item B', 'category': 'Type 2', 'value': 200}},
|
|
105
|
-
- {MITO_TODO_PLACEHOLDER}: Add remaining entries from notebook
|
|
106
|
-
+ {{'id': 3, 'name': 'Item C', 'category': 'Type 3', 'value': 300}},
|
|
107
|
-
+ {{'id': 4, 'name': 'Item D', 'category': 'Type 4', 'value': 400}},
|
|
108
|
-
+ {{'id': 5, 'name': 'Item E', 'category': 'Type 5', 'value': 500}},
|
|
109
|
-
+ {{'id': 6, 'name': 'Item F', 'category': 'Type 6', 'value': 600}},
|
|
110
|
-
+ {{'id': 7, 'name': 'Item G', 'category': 'Type 7', 'value': 700}},
|
|
111
|
-
+ {{'id': 8, 'name': 'Item H', 'category': 'Type 8', 'value': 800}},
|
|
112
|
-
+ {{'id': 9, 'name': 'Item I', 'category': 'Type 9', 'value': 900}},
|
|
113
|
-
+ {{'id': 10, 'name': 'Item J', 'category': 'Type 10', 'value': 1000}}
|
|
87
|
+
<Example 3: Deleting existing content>
|
|
88
|
+
|
|
89
|
+
```search_replace
|
|
90
|
+
>>>>>>> SEARCH
|
|
91
|
+
st.write("Old message")
|
|
92
|
+
=======
|
|
93
|
+
<<<<<<< REPLACE
|
|
114
94
|
```
|
|
115
95
|
</Example 3>
|
|
116
96
|
|
|
117
|
-
<Example 4:
|
|
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>
|
|
118
151
|
|
|
119
|
-
|
|
120
|
-
|
|
152
|
+
```search_replace
|
|
153
|
+
>>>>>>> SEARCH
|
|
121
154
|
tab1, tab2 = st.tabs(["Cat", "Dog"])
|
|
122
155
|
|
|
123
156
|
with tab1:
|
|
@@ -126,57 +159,14 @@ with tab1:
|
|
|
126
159
|
with tab2:
|
|
127
160
|
st.header("A dog")
|
|
128
161
|
st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
To consolidate into a single screen without tabs:
|
|
132
|
-
```unified_diff
|
|
133
|
-
--- a/app.py
|
|
134
|
-
+++ b/app.py
|
|
135
|
-
@@ -10,1 +10,1 @@
|
|
136
|
-
-tab1, tab2 = st.tabs(["Cat", "Dog"])
|
|
137
|
-
-
|
|
138
|
-
-with tab1:
|
|
139
|
-
- st.header("A cat")
|
|
140
|
-
- st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
141
|
-
-with tab2:
|
|
142
|
-
- st.header("A dog")
|
|
143
|
-
- st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
144
|
-
+st.header("A cat")
|
|
145
|
-
+st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
146
|
-
+st.header("A dog")
|
|
147
|
-
+st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
148
|
-
```
|
|
149
|
-
</Example 4>
|
|
150
|
-
|
|
151
|
-
<Example 5: Adding tab structure - indenting existing content>
|
|
152
|
-
|
|
153
|
-
Assume the original file has content starting at line 10:
|
|
154
|
-
```python
|
|
162
|
+
=======
|
|
155
163
|
st.header("A cat")
|
|
156
164
|
st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
157
165
|
st.header("A dog")
|
|
158
166
|
st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
167
|
+
<<<<<<< REPLACE
|
|
159
168
|
```
|
|
169
|
+
</Example 7>
|
|
160
170
|
|
|
161
|
-
|
|
162
|
-
```unified_diff
|
|
163
|
-
--- a/app.py
|
|
164
|
-
+++ b/app.py
|
|
165
|
-
@@ -10,1 +10,1 @@
|
|
166
|
-
-st.header("A cat")
|
|
167
|
-
-st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
168
|
-
-st.header("A dog")
|
|
169
|
-
-st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
170
|
-
+tab1, tab2 = st.tabs(["Cat", "Dog"])
|
|
171
|
-
+
|
|
172
|
-
+with tab1:
|
|
173
|
-
+ st.header("A cat")
|
|
174
|
-
+ st.image("https://static.streamlit.io/examples/cat.jpg", width=200)
|
|
175
|
-
+with tab2:
|
|
176
|
-
+ st.header("A dog")
|
|
177
|
-
+ st.image("https://static.streamlit.io/examples/dog.jpg", width=200)
|
|
178
|
-
```
|
|
179
|
-
</Example 5>
|
|
180
|
-
|
|
181
|
-
Your response must consist **only** of valid unified-diff block.
|
|
171
|
+
Your response must consist **only** of valid search_replace blocks.
|
|
182
172
|
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
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.streamlit_conversion.prompts.prompt_constants import
|
|
4
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import search_replace_instructions
|
|
5
5
|
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
6
6
|
|
|
7
7
|
def get_streamlit_error_correction_prompt(error: str, streamlit_app_code: str) -> str:
|
|
@@ -12,7 +12,7 @@ def get_streamlit_error_correction_prompt(error: str, streamlit_app_code: str) -
|
|
|
12
12
|
|
|
13
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
14
|
|
|
15
|
-
{
|
|
15
|
+
{search_replace_instructions}
|
|
16
16
|
|
|
17
17
|
===============================================
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ EXISTING STREAMLIT APP:
|
|
|
21
21
|
|
|
22
22
|
===============================================
|
|
23
23
|
|
|
24
|
-
Please create a
|
|
24
|
+
Please create a search/replace block that corrects this error. Please keep your fix concise:
|
|
25
25
|
{error}
|
|
26
26
|
|
|
27
27
|
"""
|
|
@@ -2,7 +2,7 @@
|
|
|
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.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER,
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import MITO_TODO_PLACEHOLDER, search_replace_instructions
|
|
6
6
|
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
7
7
|
|
|
8
8
|
def get_finish_todo_prompt(notebook: List[dict], existing_streamlit_app_code: str, todo_placeholder: str) -> str:
|
|
@@ -25,7 +25,7 @@ You have ONE and ONLY ONE opportunity to complete this TODO. If you do not finis
|
|
|
25
25
|
- If creating functions: Implement ALL required functionality
|
|
26
26
|
- If converting a visualization: Copy over ALL of the visualization code from the notebook, including all styling and formatting.
|
|
27
27
|
|
|
28
|
-
{
|
|
28
|
+
{search_replace_instructions}
|
|
29
29
|
|
|
30
30
|
===============================================
|
|
31
31
|
|
|
@@ -2,7 +2,7 @@
|
|
|
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.streamlit_conversion.prompts.prompt_constants import
|
|
5
|
+
from mito_ai.streamlit_conversion.prompts.prompt_constants import search_replace_instructions
|
|
6
6
|
from mito_ai.streamlit_conversion.prompts.prompt_utils import add_line_numbers_to_code
|
|
7
7
|
|
|
8
8
|
def get_update_existing_app_prompt(notebook: List[dict], streamlit_app_code: str, edit_prompt: str) -> str:
|
|
@@ -30,7 +30,7 @@ You have ONE and ONLY ONE opportunity to complete this edit request. If you do n
|
|
|
30
30
|
- If creating functions: Implement ALL required functionality.
|
|
31
31
|
- If converting a visualization: Copy over ALL of the visualization code from the notebook, including all styling and formatting.
|
|
32
32
|
|
|
33
|
-
{
|
|
33
|
+
{search_replace_instructions}
|
|
34
34
|
|
|
35
35
|
===============================================
|
|
36
36
|
|