mito-ai 0.1.56__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.
- mito_ai/__init__.py +2 -0
- mito_ai/_version.py +1 -1
- mito_ai/chart_wizard/__init__.py +3 -0
- mito_ai/chart_wizard/handlers.py +52 -0
- mito_ai/chart_wizard/urls.py +23 -0
- mito_ai/completions/completion_handlers/completion_handler.py +11 -2
- mito_ai/completions/completion_handlers/scratchpad_result_handler.py +66 -0
- mito_ai/completions/handlers.py +5 -0
- mito_ai/completions/models.py +23 -2
- mito_ai/completions/prompt_builders/agent_smart_debug_prompt.py +5 -3
- mito_ai/completions/prompt_builders/agent_system_message.py +97 -5
- mito_ai/completions/prompt_builders/chart_conversion_prompt.py +27 -0
- mito_ai/completions/prompt_builders/chat_system_message.py +2 -0
- mito_ai/completions/prompt_builders/prompt_constants.py +28 -0
- mito_ai/completions/prompt_builders/scratchpad_result_prompt.py +17 -0
- mito_ai/utils/provider_utils.py +8 -1
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/build_log.json +102 -102
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/package.json +2 -2
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/package.json.orig +1 -1
- mito_ai-0.1.56.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.dfd7975de75d64db80d6.js → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.9d26322f3e78beb2b666.js +2371 -257
- mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.9d26322f3e78beb2b666.js.map +1 -0
- mito_ai-0.1.56.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.1e7b5cf362385f109883.js → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.79c1ea8a3cda73a4cb6f.js +17 -17
- mito_ai-0.1.56.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.1e7b5cf362385f109883.js.map → mito_ai-0.1.57.data/data/share/jupyter/labextensions/mito_ai/static/remoteEntry.79c1ea8a3cda73a4cb6f.js.map +1 -1
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/themes/mito_ai/index.css +7 -2
- {mito_ai-0.1.56.dist-info → mito_ai-0.1.57.dist-info}/METADATA +1 -1
- {mito_ai-0.1.56.dist-info → mito_ai-0.1.57.dist-info}/RECORD +51 -45
- mito_ai-0.1.56.data/data/share/jupyter/labextensions/mito_ai/static/lib_index_js.dfd7975de75d64db80d6.js.map +0 -1
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/etc/jupyter/jupyter_server_config.d/mito_ai.json +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/schemas/mito_ai/toolbar-buttons.json +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/node_modules_process_browser_js.4b128e94d31a81ebd209.js.map +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style.js +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.f5d476ac514294615881.js +0 -0
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/style_index_js.f5d476ac514294615881.js.map +0 -0
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/static/vendors-node_modules_semver_index_js.3f6754ac5116d47de76b.js +0 -0
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.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
- {mito_ai-0.1.56.data → mito_ai-0.1.57.data}/data/share/jupyter/labextensions/mito_ai/themes/mito_ai/index.js +0 -0
- {mito_ai-0.1.56.dist-info → mito_ai-0.1.57.dist-info}/WHEEL +0 -0
- {mito_ai-0.1.56.dist-info → mito_ai-0.1.57.dist-info}/entry_points.txt +0 -0
- {mito_ai-0.1.56.dist-info → mito_ai-0.1.57.dist-info}/licenses/LICENSE +0 -0
mito_ai/__init__.py
CHANGED
|
@@ -19,6 +19,7 @@ from mito_ai.app_manager.handlers import AppManagerHandler
|
|
|
19
19
|
from mito_ai.file_uploads.urls import get_file_uploads_urls
|
|
20
20
|
from mito_ai.user.urls import get_user_urls
|
|
21
21
|
from mito_ai.chat_history.urls import get_chat_history_urls
|
|
22
|
+
from mito_ai.chart_wizard.urls import get_chart_wizard_urls
|
|
22
23
|
|
|
23
24
|
# Force Matplotlib to use the Jupyter inline backend.
|
|
24
25
|
# Background: importing Streamlit sets os.environ["MPLBACKEND"] = "Agg" very early.
|
|
@@ -109,6 +110,7 @@ def _load_jupyter_server_extension(server_app) -> None: # type: ignore
|
|
|
109
110
|
handlers.extend(get_file_uploads_urls(base_url)) # type: ignore
|
|
110
111
|
handlers.extend(get_user_urls(base_url)) # type: ignore
|
|
111
112
|
handlers.extend(get_chat_history_urls(base_url, global_message_history)) # type: ignore
|
|
113
|
+
handlers.extend(get_chart_wizard_urls(base_url, open_ai_provider)) # type: ignore
|
|
112
114
|
|
|
113
115
|
web_app.add_handlers(host_pattern, handlers)
|
|
114
116
|
server_app.log.info("Loaded the mito_ai server extension")
|
mito_ai/_version.py
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import tornado
|
|
6
|
+
from typing import List
|
|
7
|
+
from jupyter_server.base.handlers import APIHandler
|
|
8
|
+
from openai.types.chat import ChatCompletionMessageParam
|
|
9
|
+
from mito_ai.completions.providers import OpenAIProvider
|
|
10
|
+
from mito_ai.utils.anthropic_utils import FAST_ANTHROPIC_MODEL
|
|
11
|
+
from mito_ai.completions.models import MessageType
|
|
12
|
+
from mito_ai.completions.prompt_builders.chart_conversion_prompt import create_chart_conversion_prompt
|
|
13
|
+
|
|
14
|
+
class ChartWizardHandler(APIHandler):
|
|
15
|
+
def initialize(self, llm: OpenAIProvider) -> None:
|
|
16
|
+
"""Initialize the handler with the LLM provider."""
|
|
17
|
+
super().initialize()
|
|
18
|
+
self._llm = llm
|
|
19
|
+
|
|
20
|
+
@tornado.web.authenticated
|
|
21
|
+
async def post(self) -> None:
|
|
22
|
+
"""POST endpoint that receives code from the frontend and sends it to LLM."""
|
|
23
|
+
try:
|
|
24
|
+
data = json.loads(self.request.body.decode('utf-8'))
|
|
25
|
+
code = data.get('code', '')
|
|
26
|
+
|
|
27
|
+
# Create prompt using the prompt builder
|
|
28
|
+
prompt = create_chart_conversion_prompt(code)
|
|
29
|
+
|
|
30
|
+
# Call LLM
|
|
31
|
+
messages: List[ChatCompletionMessageParam] = [{"role": "user", "content": prompt}]
|
|
32
|
+
converted_code = await self._llm.request_completions(
|
|
33
|
+
messages=messages,
|
|
34
|
+
model=FAST_ANTHROPIC_MODEL,
|
|
35
|
+
message_type=MessageType.CHAT,
|
|
36
|
+
thread_id=None
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Return the converted code
|
|
40
|
+
self.write({
|
|
41
|
+
"message": "Code converted successfully",
|
|
42
|
+
"converted_code": converted_code
|
|
43
|
+
})
|
|
44
|
+
self.finish()
|
|
45
|
+
except json.JSONDecodeError:
|
|
46
|
+
self.set_status(400)
|
|
47
|
+
self.write({"error": "Invalid JSON in request body"})
|
|
48
|
+
self.finish()
|
|
49
|
+
except Exception as e:
|
|
50
|
+
self.set_status(500)
|
|
51
|
+
self.write({"error": str(e)})
|
|
52
|
+
self.finish()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Copyright (c) Saga Inc.
|
|
2
|
+
# Distributed under the terms of the GNU Affero General Public License v3.0 License.
|
|
3
|
+
|
|
4
|
+
from typing import List, Tuple, Any
|
|
5
|
+
from jupyter_server.utils import url_path_join
|
|
6
|
+
from mito_ai.chart_wizard.handlers import ChartWizardHandler
|
|
7
|
+
from mito_ai.completions.providers import OpenAIProvider
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_chart_wizard_urls(base_url: str, llm: OpenAIProvider) -> List[Tuple[str, Any, dict]]:
|
|
11
|
+
"""Get all chart wizard related URL patterns.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
base_url: The base URL for the Jupyter server
|
|
15
|
+
llm: The OpenAI provider instance
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
List of (url_pattern, handler_class, handler_kwargs) tuples
|
|
19
|
+
"""
|
|
20
|
+
BASE_URL = base_url + "/mito-ai"
|
|
21
|
+
return [
|
|
22
|
+
(url_path_join(BASE_URL, "chart-wizard"), ChartWizardHandler, {"llm": llm}),
|
|
23
|
+
]
|
|
@@ -3,11 +3,20 @@
|
|
|
3
3
|
|
|
4
4
|
from typing import Protocol, TypeVar
|
|
5
5
|
from abc import abstractmethod, ABCMeta
|
|
6
|
-
from mito_ai.completions.models import ChatMessageMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, InlineCompleterMetadata, AgentSmartDebugMetadata
|
|
6
|
+
from mito_ai.completions.models import ChatMessageMetadata, ScratchpadResultMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, InlineCompleterMetadata, AgentSmartDebugMetadata
|
|
7
7
|
from mito_ai.completions.providers import OpenAIProvider
|
|
8
8
|
from mito_ai.completions.message_history import GlobalMessageHistory
|
|
9
9
|
|
|
10
|
-
T = TypeVar('T',
|
|
10
|
+
T = TypeVar('T',
|
|
11
|
+
ChatMessageMetadata,
|
|
12
|
+
SmartDebugMetadata,
|
|
13
|
+
CodeExplainMetadata,
|
|
14
|
+
AgentExecutionMetadata,
|
|
15
|
+
AgentSmartDebugMetadata,
|
|
16
|
+
InlineCompleterMetadata,
|
|
17
|
+
ScratchpadResultMetadata,
|
|
18
|
+
contravariant=True
|
|
19
|
+
)
|
|
11
20
|
|
|
12
21
|
class CompletionHandler(Protocol[T], metaclass=ABCMeta):
|
|
13
22
|
"""Protocol defining the interface for completion handlers.
|
|
@@ -0,0 +1,66 @@
|
|
|
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, Literal, Union
|
|
5
|
+
from openai.types.chat import ChatCompletionMessageParam
|
|
6
|
+
from mito_ai.completions.models import ScratchpadResultMetadata, MessageType, ResponseFormatInfo, AgentResponse
|
|
7
|
+
from mito_ai.completions.prompt_builders.scratchpad_result_prompt import create_scratchpad_result_prompt
|
|
8
|
+
from mito_ai.completions.providers import OpenAIProvider
|
|
9
|
+
from mito_ai.completions.message_history import GlobalMessageHistory
|
|
10
|
+
from mito_ai.completions.completion_handlers.completion_handler import CompletionHandler
|
|
11
|
+
from mito_ai.completions.completion_handlers.utils import append_agent_system_message, create_ai_optimized_message
|
|
12
|
+
|
|
13
|
+
__all__ = ["get_scratchpad_result_completion"]
|
|
14
|
+
|
|
15
|
+
class ScratchpadResultHandler(CompletionHandler[ScratchpadResultMetadata]):
|
|
16
|
+
"""Handler for scratchpad result completions."""
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
async def get_completion(
|
|
20
|
+
metadata: ScratchpadResultMetadata,
|
|
21
|
+
provider: OpenAIProvider,
|
|
22
|
+
message_history: GlobalMessageHistory,
|
|
23
|
+
model: str
|
|
24
|
+
) -> str:
|
|
25
|
+
"""Get a scratchpad result completion from the AI provider."""
|
|
26
|
+
|
|
27
|
+
if metadata.index is not None:
|
|
28
|
+
message_history.truncate_histories(
|
|
29
|
+
thread_id=metadata.threadId,
|
|
30
|
+
index=metadata.index
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Add the system message if it doesn't already exist
|
|
34
|
+
await append_agent_system_message(message_history, model, provider, metadata.threadId, True)
|
|
35
|
+
|
|
36
|
+
# Create the prompt
|
|
37
|
+
prompt = create_scratchpad_result_prompt(metadata)
|
|
38
|
+
display_prompt = ""
|
|
39
|
+
|
|
40
|
+
# Add the prompt to the message history
|
|
41
|
+
new_ai_optimized_message = create_ai_optimized_message(prompt, None, None)
|
|
42
|
+
new_display_optimized_message: ChatCompletionMessageParam = {"role": "user", "content": display_prompt}
|
|
43
|
+
|
|
44
|
+
await message_history.append_message(new_ai_optimized_message, new_display_optimized_message, model, provider, metadata.threadId)
|
|
45
|
+
|
|
46
|
+
# Get the completion
|
|
47
|
+
completion = await provider.request_completions(
|
|
48
|
+
messages=message_history.get_ai_optimized_history(metadata.threadId),
|
|
49
|
+
model=model,
|
|
50
|
+
response_format_info=ResponseFormatInfo(
|
|
51
|
+
name='agent_response',
|
|
52
|
+
format=AgentResponse
|
|
53
|
+
),
|
|
54
|
+
message_type=MessageType.AGENT_SCRATCHPAD_RESULT,
|
|
55
|
+
user_input="",
|
|
56
|
+
thread_id=metadata.threadId
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
ai_response_message: ChatCompletionMessageParam = {"role": "assistant", "content": completion}
|
|
60
|
+
|
|
61
|
+
await message_history.append_message(ai_response_message, ai_response_message, model, provider, metadata.threadId)
|
|
62
|
+
|
|
63
|
+
return completion
|
|
64
|
+
|
|
65
|
+
# Use the static method directly
|
|
66
|
+
get_scratchpad_result_completion = ScratchpadResultHandler.get_completion
|
mito_ai/completions/handlers.py
CHANGED
|
@@ -34,6 +34,7 @@ from mito_ai.completions.models import (
|
|
|
34
34
|
CodeExplainMetadata,
|
|
35
35
|
AgentExecutionMetadata,
|
|
36
36
|
InlineCompleterMetadata,
|
|
37
|
+
ScratchpadResultMetadata,
|
|
37
38
|
MessageType
|
|
38
39
|
)
|
|
39
40
|
from mito_ai.completions.providers import OpenAIProvider
|
|
@@ -45,6 +46,7 @@ from mito_ai.completions.completion_handlers.code_explain_handler import get_cod
|
|
|
45
46
|
from mito_ai.completions.completion_handlers.inline_completer_handler import get_inline_completion
|
|
46
47
|
from mito_ai.completions.completion_handlers.agent_execution_handler import get_agent_execution_completion
|
|
47
48
|
from mito_ai.completions.completion_handlers.agent_auto_error_fixup_handler import get_agent_auto_error_fixup_completion
|
|
49
|
+
from mito_ai.completions.completion_handlers.scratchpad_result_handler import get_scratchpad_result_completion
|
|
48
50
|
from mito_ai.utils.telemetry_utils import identify
|
|
49
51
|
|
|
50
52
|
FALLBACK_MODEL = "gpt-4.1" # Default model to use for safety
|
|
@@ -314,6 +316,9 @@ class CompletionHandler(JupyterHandler, WebSocketHandler):
|
|
|
314
316
|
elif type == MessageType.AGENT_AUTO_ERROR_FIXUP:
|
|
315
317
|
agent_auto_error_fixup_metadata = AgentSmartDebugMetadata(**metadata_dict)
|
|
316
318
|
completion = await get_agent_auto_error_fixup_completion(agent_auto_error_fixup_metadata, self._llm, self._message_history, model)
|
|
319
|
+
elif type == MessageType.AGENT_SCRATCHPAD_RESULT:
|
|
320
|
+
scratchpad_result_metadata = ScratchpadResultMetadata(**metadata_dict)
|
|
321
|
+
completion = await get_scratchpad_result_completion(scratchpad_result_metadata, self._llm, self._message_history, model)
|
|
317
322
|
elif type == MessageType.INLINE_COMPLETION:
|
|
318
323
|
inline_completer_metadata = InlineCompleterMetadata(**metadata_dict)
|
|
319
324
|
completion = await get_inline_completion(inline_completer_metadata, self._llm, self._message_history, model)
|
mito_ai/completions/models.py
CHANGED
|
@@ -29,13 +29,26 @@ class CellUpdate(BaseModel):
|
|
|
29
29
|
# for now and rely on the AI to respond with the correct types, following the format
|
|
30
30
|
# that we show it in the system prompt.
|
|
31
31
|
class AgentResponse(BaseModel):
|
|
32
|
-
type: Literal[
|
|
32
|
+
type: Literal[
|
|
33
|
+
'cell_update',
|
|
34
|
+
'get_cell_output',
|
|
35
|
+
'run_all_cells',
|
|
36
|
+
'finished_task',
|
|
37
|
+
'create_streamlit_app',
|
|
38
|
+
'edit_streamlit_app',
|
|
39
|
+
'ask_user_question',
|
|
40
|
+
'scratchpad',
|
|
41
|
+
]
|
|
33
42
|
message: str
|
|
34
43
|
cell_update: Optional[CellUpdate]
|
|
35
44
|
get_cell_output_cell_id: Optional[str]
|
|
36
45
|
next_steps: Optional[List[str]]
|
|
37
46
|
analysis_assumptions: Optional[List[str]]
|
|
38
47
|
streamlit_app_prompt: Optional[str]
|
|
48
|
+
question: Optional[str]
|
|
49
|
+
answers: Optional[List[str]]
|
|
50
|
+
scratchpad_code: Optional[str]
|
|
51
|
+
scratchpad_summary: Optional[str]
|
|
39
52
|
|
|
40
53
|
|
|
41
54
|
@dataclass(frozen=True)
|
|
@@ -67,6 +80,7 @@ class MessageType(Enum):
|
|
|
67
80
|
STREAMLIT_CONVERSION = "streamlit_conversion"
|
|
68
81
|
STOP_AGENT = "stop_agent"
|
|
69
82
|
DEPLOY_APP = "deploy_app"
|
|
83
|
+
AGENT_SCRATCHPAD_RESULT = "agent:scratchpad-result"
|
|
70
84
|
|
|
71
85
|
|
|
72
86
|
@dataclass(frozen=True)
|
|
@@ -136,13 +150,20 @@ class CodeExplainMetadata():
|
|
|
136
150
|
activeCellCode: Optional[str] = None
|
|
137
151
|
|
|
138
152
|
@dataclass(frozen=True)
|
|
139
|
-
class InlineCompleterMetadata():
|
|
153
|
+
class InlineCompleterMetadata():
|
|
140
154
|
promptType: Literal['inline_completion']
|
|
141
155
|
prefix: str
|
|
142
156
|
suffix: str
|
|
143
157
|
variables: Optional[List[str]] = None
|
|
144
158
|
files: Optional[List[str]] = None
|
|
145
159
|
|
|
160
|
+
@dataclass(frozen=True)
|
|
161
|
+
class ScratchpadResultMetadata():
|
|
162
|
+
promptType: Literal['agent:scratchpad-result']
|
|
163
|
+
threadId: ThreadID
|
|
164
|
+
scratchpadResult: str
|
|
165
|
+
index: Optional[int] = None
|
|
166
|
+
|
|
146
167
|
@dataclass(frozen=True)
|
|
147
168
|
class CompletionRequest:
|
|
148
169
|
"""
|
|
@@ -22,12 +22,12 @@ def create_agent_smart_debug_prompt(md: AgentSmartDebugMetadata) -> str:
|
|
|
22
22
|
|
|
23
23
|
Use this strategy for this message only. After this message, continue using the original set of instructions that I provided you.
|
|
24
24
|
|
|
25
|
-
It is very important that
|
|
25
|
+
It is very important that when fixing this error, you do not change the original intent of the code cell.
|
|
26
26
|
|
|
27
27
|
To fix this error, take the following approach:
|
|
28
28
|
Step 1: ERROR ANALYSIS: Analyze the error message to identify why the code cell errored.
|
|
29
29
|
Step 2: INTENT PRESERVATION: Make sure you understand the intent of the CELL_UPDATE so that you can be sure to preserve it when you create a new CELL_UPDATE
|
|
30
|
-
Step 3: ERROR CORRECTION: Respond with a new CELL_UPDATE that is applied to the same cell as the erroring CELL_UPDATE.
|
|
30
|
+
Step 3: ERROR CORRECTION: Respond with a new CELL_UPDATE that is applied to the same cell as the erroring CELL_UPDATE or use the ASK_USER_QUESTION tool to get more information about how to proceed.
|
|
31
31
|
|
|
32
32
|
INSTRUCTIONS FOR EACH PHASE
|
|
33
33
|
|
|
@@ -43,13 +43,15 @@ INTENT PRESERVATION:
|
|
|
43
43
|
|
|
44
44
|
ERROR CORRECTION:
|
|
45
45
|
|
|
46
|
-
-
|
|
46
|
+
- Use one of your tools to correct the error or get more information from the user on how to proceed.
|
|
47
|
+
- If you use the CELL_UPDATE tool, you must reutn the full updated version of cell {md.error_message_producing_code_cell_id} with the error fixed and a short explanation of the error.
|
|
47
48
|
- You can only update code in {md.error_message_producing_code_cell_id}. You are unable to edit the code in any other cell when resolving this error.
|
|
48
49
|
- Propose a solution that fixes the error and does not change the user's intent.
|
|
49
50
|
- Make the solution as simple as possible.
|
|
50
51
|
- Reuse as much of the existing code as possible.
|
|
51
52
|
- DO NOT ADD TEMPORARY COMMENTS like '# Fixed the typo here' or '# Added this line to fix the error'
|
|
52
53
|
- If you encounter a ModuleNotFoundError, you can install the package by adding the the following line to the top of the code cell: `!pip install <package_name> --quiet`.
|
|
54
|
+
- If the error is not resolvable without getting more information from the user, you can respond with a ASK_USER_QUESTION tool call.
|
|
53
55
|
- If you encounter a NameError, you can use the RUN_ALL_CELLS tool to run all cells from the top of the notebook to the bottom to bring the variable into scope.
|
|
54
56
|
RUN_ALL_CELLS:
|
|
55
57
|
When you want to execute all cells in the notebook from top to bottom, respond with this format:
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
from typing import List
|
|
5
5
|
from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
|
|
6
6
|
from mito_ai.completions.prompt_builders.prompt_constants import (
|
|
7
|
+
CHART_CONFIG_RULES,
|
|
7
8
|
CITATION_RULES,
|
|
8
9
|
CELL_REFERENCE_RULES,
|
|
9
10
|
get_database_rules
|
|
10
11
|
)
|
|
11
12
|
from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
|
|
12
13
|
|
|
13
|
-
|
|
14
14
|
def create_agent_system_message_prompt(isChromeBrowser: bool) -> str:
|
|
15
15
|
|
|
16
16
|
# The GET_CELL_OUTPUT tool only works on Chrome based browsers.
|
|
@@ -28,6 +28,8 @@ The user is going to ask you to guide them as they complete a task. You will hel
|
|
|
28
28
|
You have access to a set of tools that you can use to accomplish the task you've been given. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
|
|
29
29
|
|
|
30
30
|
Each time you use a tool, except for the finished_task tool, the user will execute the tool and provide you with updated information about the notebook and variables defined in the kernel to help you decide what to do next."""))
|
|
31
|
+
|
|
32
|
+
sections.append(SG.Generic("Chart Config Rules", CHART_CONFIG_RULES))
|
|
31
33
|
|
|
32
34
|
sections.append(SG.Generic("TOOL: CELL_UPDATE", """
|
|
33
35
|
|
|
@@ -223,6 +225,85 @@ Important information:
|
|
|
223
225
|
4. If running all cells results in an error, the system will automatically handle the error through the normal error fixing process.
|
|
224
226
|
5. Do not use this tool repeatedly if it continues to produce errors - instead, focus on fixing the specific error that occurred."""))
|
|
225
227
|
|
|
228
|
+
# SCRATCHPAD tool
|
|
229
|
+
sections.append(SG.Generic("TOOL: SCRATCHPAD", """
|
|
230
|
+
When you need to explore data, check the filesystem, analyze mappings, or look up values without leaving code in the notebook, use the SCRATCHPAD tool.
|
|
231
|
+
|
|
232
|
+
Format:
|
|
233
|
+
{{
|
|
234
|
+
type: 'scratchpad',
|
|
235
|
+
message: str,
|
|
236
|
+
scratchpad_code: str,
|
|
237
|
+
scratchpad_summary: str
|
|
238
|
+
}}
|
|
239
|
+
|
|
240
|
+
Important information:
|
|
241
|
+
1. The scratchpad_code will execute silently against the same kernel as your notebook, so you have access to all variables and dataframes.
|
|
242
|
+
2. Any variables you create in scratchpad code MUST be prefixed with "scratch_" (e.g., use "scratch_temp_df" not "temp_df", use "scratch_files" not "files"). This prevents them from appearing in the variable list and confusing future decisions.
|
|
243
|
+
3. CRITICAL: Do NOT modify existing variables. If you need to explore or modify data, create a copy with the scratch_ prefix first. For example, use "scratch_df = df.copy()" and then modify scratch_df, rather than modifying df directly. This ensures existing variables remain unchanged.
|
|
244
|
+
4. Structure your code to print the information you need. Use print() statements for output that will be captured.
|
|
245
|
+
5. If you need structured data, consider using JSON: `import json; print(json.dumps(your_data))`
|
|
246
|
+
6. The results (including any errors) will be included in your next message, so you can use them to inform your next action.
|
|
247
|
+
7. If the code errors, the error message and traceback will be included in the results. You can then decide to fix the code and try again, ask the user a question, or take a different approach.
|
|
248
|
+
8. Use scratchpad for exploration work that doesn't belong in the final notebook. Once you have the information, create clean CELL_UPDATES with hardcoded values.
|
|
249
|
+
9. The scratchpad_summary must be a very short phrase (1–5 words maximum) that begins with a verb ending in "-ing" (e.g., "Checking files", "Exploring data", "Analyzing mappings", "Looking up values"). Avoid full sentences or explanations. This should read like a quick commit message or code label, not a description.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
{{
|
|
253
|
+
type: 'scratchpad',
|
|
254
|
+
message: "I'll check what files are in the current directory to find the data file.",
|
|
255
|
+
scratchpad_code: "import os\\nscratch_files = os.listdir('.')\\nprint('Files:', scratch_files)\\nfor scratch_file in scratch_files:\\n if scratch_file.endswith('.csv'):\\n print(f'CSV file found: {scratch_file}')",
|
|
256
|
+
scratchpad_summary: "Checking files"
|
|
257
|
+
}}
|
|
258
|
+
|
|
259
|
+
Example with dataframe exploration:
|
|
260
|
+
{{
|
|
261
|
+
type: 'scratchpad',
|
|
262
|
+
message: "I'll explore the dataframe structure to understand the columns.",
|
|
263
|
+
scratchpad_code: "scratch_df = df.copy()\\nprint('Columns:', scratch_df.columns.tolist())\\nprint('Shape:', scratch_df.shape)\\nprint('First few rows:')\\nprint(scratch_df.head())",
|
|
264
|
+
scratchpad_summary: "Exploring dataframe"
|
|
265
|
+
}}
|
|
266
|
+
"""))
|
|
267
|
+
|
|
268
|
+
# ASK_USER_QUESTION tool
|
|
269
|
+
sections.append(SG.Generic("TOOL: ASK_USER_QUESTION", f"""
|
|
270
|
+
|
|
271
|
+
When you have a specific question that you the user to answer so that you can figure out how to proceed in your work, you can respond in this format:
|
|
272
|
+
|
|
273
|
+
{{
|
|
274
|
+
type: 'ask_user_question',
|
|
275
|
+
message: str,
|
|
276
|
+
question: str,
|
|
277
|
+
answers: Optional[List[str]]
|
|
278
|
+
}}
|
|
279
|
+
|
|
280
|
+
Important information:
|
|
281
|
+
1. Use this tool when you need clarification from the user on how to proceed. Common scenarios include:
|
|
282
|
+
- A file or resource doesn't exist and you need to know how to proceed
|
|
283
|
+
- There are multiple valid approaches and you want the user to choose
|
|
284
|
+
- You need clarification on ambiguous requirements
|
|
285
|
+
- You encounter an error that requires user input to resolve
|
|
286
|
+
2. The message should be a short description of what you've tried so far and why you need to ask the user a question now. This helps the user understand the context. The message provides background information but should NOT contain the actual question.
|
|
287
|
+
3. The question field is REQUIRED and must always be provided. It cannot be null or empty. The question should be a clear, direct question that ends with a question mark. It should be concise and direct - do NOT include instructions or explanations in the question itself, as the answer options should make it clear what information is needed. For example, instead of "Which companies would you like me to compare Meta's stock performance against? Please provide a list of company names or stock tickers", just ask "Which companies would you like me to compare Meta's stock performance against?" The answer options will make it clear that company names or tickers are expected.
|
|
288
|
+
4. The message and question serve different purposes: the message provides context about what you've tried, while the question is the actual question the user needs to answer. If your message contains a question, extract that question into the question field. For example, if your message says "I need to understand how you'd like to access the tweets", your question should be something like "How would you like to access the tweets?"
|
|
289
|
+
5. Use the optional list of answers to provide the user multiple choice options to choose from. If it is an open ended question that you cannot create helpful multiple choice answers for, leave it blank and the user will respond in the text input field.
|
|
290
|
+
6. When creating multiple choice answer options:
|
|
291
|
+
- Make each option distinct and meaningful - avoid options that differ only slightly from each other.
|
|
292
|
+
- If there are no obvious predefined answers, leave it blank and the user will respond in the text input field.
|
|
293
|
+
7. After the user responds to your question, you will receive their response in the next message and can continue with the task based on their answer.
|
|
294
|
+
8. Do not use this tool for trivial questions that you can infer from context. Only use it when you cannot proceed in the user's task without answering your specific question first.
|
|
295
|
+
|
|
296
|
+
<Example>
|
|
297
|
+
{{
|
|
298
|
+
type: 'ask_user_question',
|
|
299
|
+
message: "I tried importing apple_prices.csv and confirmed that it does not exist in the current working directory.",
|
|
300
|
+
question: "The file apple_prices.csv does not exist. How do you want to proceed?",
|
|
301
|
+
answers: ["Pull Apple Stock prices using yfinance API", "Create placeholder data", "Skip this step"]
|
|
302
|
+
}}
|
|
303
|
+
</Example>
|
|
304
|
+
|
|
305
|
+
"""))
|
|
306
|
+
|
|
226
307
|
# CREATE_STREAMLIT_APP tool
|
|
227
308
|
sections.append(SG.Generic("TOOL: CREATE_STREAMLIT_APP", """
|
|
228
309
|
|
|
@@ -316,18 +397,29 @@ Important information:
|
|
|
316
397
|
# RULES section
|
|
317
398
|
sections.append(SG.Generic("RULES", """
|
|
318
399
|
- You are working in a Jupyter Lab environment in a .ipynb file.
|
|
319
|
-
- In each message you can choose one of the tools to respond with.
|
|
400
|
+
- In each message you can choose one of the tools to respond with. YOU WILL GET TO SEND MULTIPLE MESSAGES TO THE USER TO ACCOMPLISH YOUR TASK SO DO NOT TRY TO ACCOMPLISH YOUR TASK IN A SINGLE MESSAGE.
|
|
320
401
|
- After you send a CELL_UPDATE, the user will send you a message with the updated variables, code, and files in the current directory. You will use this information to decide what to do next, so it is critical that you wait for the user's response after each CELL_UPDATE before deciding your next action.
|
|
321
|
-
- When updating code, keep as much of the original code as possible and do not recreate variables that already exist.
|
|
322
402
|
- When writing the message, do not explain to the user how to use the CELL_UPDATE or FINISHED_TASK response, they will already know how to use them. Just provide a summary of your thought process. Do not reference any Cell IDs in the message.
|
|
323
403
|
- When writing the message, do not include leading words like "Explanation:" or "Thought process:". Just provide a summary of your thought process.
|
|
324
404
|
- When writing the message, use tickmarks when referencing specific variable names. For example, write `sales_df` instead of "sales_df" or just sales_df."""))
|
|
325
405
|
|
|
326
406
|
# CODE STYLE section
|
|
327
407
|
sections.append(SG.Generic("CODE STYLE", """
|
|
328
|
-
-
|
|
408
|
+
- When updating code, keep as much of the original code as possible and do not recreate variables that already exist.
|
|
329
409
|
- When you want to display a dataframe to the user, just write the dataframe on the last line of the code cell instead of writing print(<dataframe name>). Jupyter will automatically display the dataframe in the notebook.
|
|
330
|
-
- When importing matplotlib, write the code `%matplotlib inline` to make sure the graphs render in Jupyter.
|
|
410
|
+
- When importing matplotlib, write the code `%matplotlib inline` to make sure the graphs render in Jupyter.
|
|
411
|
+
- Avoid adding try/except blocks unless there is a very good reason. Do not use them for things like:
|
|
412
|
+
```
|
|
413
|
+
try:
|
|
414
|
+
df = pd.read_csv('my_data.csv')
|
|
415
|
+
except:
|
|
416
|
+
print("File not found")
|
|
417
|
+
```
|
|
418
|
+
Instead, just let the cell error and use the ask_user_question tool to figure out how to proceed.
|
|
419
|
+
- Avoid defensive if statements like checking if a variable exists in the globals or verifying that a column exists. Instead, just let the code error and use the ask_user_question tool to figure out how to proceed.
|
|
420
|
+
- Do not simulate the data without the user explicity asking you to do so.
|
|
421
|
+
- Do not replace broken code with print statements that explain the issue. Instead, leave the broken code in the notebook and use the ask_user_question tools to communicate the issue to the user and figure out how to proceed.
|
|
422
|
+
"""))
|
|
331
423
|
|
|
332
424
|
# CITATION_RULES
|
|
333
425
|
sections.append(SG.Generic("Citation Rules", f"""{CITATION_RULES}
|
|
@@ -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)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from typing import List
|
|
5
5
|
from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
|
|
6
6
|
from mito_ai.completions.prompt_builders.prompt_constants import (
|
|
7
|
+
CHART_CONFIG_RULES,
|
|
7
8
|
CHAT_CODE_FORMATTING_RULES,
|
|
8
9
|
CITATION_RULES,
|
|
9
10
|
CELL_REFERENCE_RULES,
|
|
@@ -31,6 +32,7 @@ Other useful information:
|
|
|
31
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.
|
|
32
33
|
"""))
|
|
33
34
|
|
|
35
|
+
sections.append(SG.Generic("Chart Config Rules", CHART_CONFIG_RULES))
|
|
34
36
|
sections.append(SG.Generic("DatabaseRules", get_database_rules()))
|
|
35
37
|
sections.append(SG.Generic("Citation Rules", CITATION_RULES))
|
|
36
38
|
sections.append(SG.Generic("Cell Reference Rules", CELL_REFERENCE_RULES))
|
|
@@ -11,6 +11,34 @@ import json
|
|
|
11
11
|
from typing import Final
|
|
12
12
|
from mito_ai.utils.schema import MITO_FOLDER
|
|
13
13
|
|
|
14
|
+
CHART_CONFIG_RULES = """
|
|
15
|
+
When creating a matplotlib chart, you must use the `# === CHART CONFIG ===` and `# === END CONFIG ===` markers to indicate the start and end of the chart configuration section.
|
|
16
|
+
|
|
17
|
+
The chart configuration section is a list of variables used to customize the chart. This includes the titles, labels, colors, and any variables that affect the chart's appearance.
|
|
18
|
+
|
|
19
|
+
Rules:
|
|
20
|
+
- All imports must appear at the top, before the chart configuration section.
|
|
21
|
+
- Variables with multiple words should be underscore-separated.
|
|
22
|
+
- All colors should be in hex format (e.g., "#3498db"). Use quotes around the hex string: COLOR = "#3498db" or COLOR = '#3498db'. Do NOT nest quotes.
|
|
23
|
+
- Variables can only be strings, numbers, booleans, tuples, or lists.
|
|
24
|
+
- NEVER include comments on the same line as a variable assignment. Each variable assignment must be on its own line with no trailing comments.
|
|
25
|
+
- For string values, use either single or double quotes (e.g., TITLE = "Sales by Product" or TITLE = 'Sales by Product'). Do not use nested quotes (e.g., do NOT use '"value"').
|
|
26
|
+
|
|
27
|
+
Common Mistakes to Avoid:
|
|
28
|
+
- WRONG: COLOR = '"#1877F2" # Meta Blue' (nested quotes and inline comment)
|
|
29
|
+
- WRONG: COLOR = "#1877F2" # Meta Blue (inline comment)
|
|
30
|
+
- WRONG: COLOR = '"#1877F2"' (nested quotes)
|
|
31
|
+
- CORRECT: COLOR = "#1877F2" (simple hex string, no nested quotes, no inline comments)
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
# === CHART CONFIG ===
|
|
35
|
+
TITLE = "Sales by Product"
|
|
36
|
+
X_LABEL = "Product"
|
|
37
|
+
Y_LABEL = "Sales"
|
|
38
|
+
BAR_COLOR = "#000000"
|
|
39
|
+
# === END CONFIG ===
|
|
40
|
+
"""
|
|
41
|
+
|
|
14
42
|
CITATION_RULES = """
|
|
15
43
|
It is important that the user is able to verify any insights that you share with them about their data. To make this easy for the user, you must cite the lines of code that you are drawing the insight from. To provide a citation, use one of the following formats inline in your response:
|
|
16
44
|
|
|
@@ -0,0 +1,17 @@
|
|
|
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.models import ScratchpadResultMetadata
|
|
6
|
+
from mito_ai.completions.prompt_builders.prompt_section_registry import SG, Prompt
|
|
7
|
+
from mito_ai.completions.prompt_builders.prompt_section_registry.base import PromptSection
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def create_scratchpad_result_prompt(md: ScratchpadResultMetadata) -> str:
|
|
11
|
+
sections: List[PromptSection] = [
|
|
12
|
+
SG.Generic("Reminder", "Continue working on your current task using the scratchpad results below."),
|
|
13
|
+
SG.Generic("Scratchpad Result", f"The result of your scratchpad is: {md.scratchpadResult}"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
prompt = Prompt(sections)
|
|
17
|
+
return str(prompt)
|
mito_ai/utils/provider_utils.py
CHANGED
|
@@ -36,7 +36,14 @@ def does_message_require_fast_model(message_type: MessageType) -> bool:
|
|
|
36
36
|
so they don't slow down the user's experience.
|
|
37
37
|
"""
|
|
38
38
|
|
|
39
|
-
if message_type in (
|
|
39
|
+
if message_type in (
|
|
40
|
+
MessageType.CHAT,
|
|
41
|
+
MessageType.SMART_DEBUG,
|
|
42
|
+
MessageType.CODE_EXPLAIN,
|
|
43
|
+
MessageType.AGENT_EXECUTION,
|
|
44
|
+
MessageType.AGENT_SCRATCHPAD_RESULT,
|
|
45
|
+
MessageType.AGENT_AUTO_ERROR_FIXUP,
|
|
46
|
+
):
|
|
40
47
|
return False
|
|
41
48
|
elif message_type in (MessageType.INLINE_COMPLETION, MessageType.CHAT_NAME_GENERATION):
|
|
42
49
|
return True
|