Skip to content

Commit 2afe5b1

Browse files
authored
Merge pull request #1571 from mito-ds/fix/agent-error-fixuo
Fix/agent error fixup
2 parents cf3c6cc + 7d04602 commit 2afe5b1

File tree

9 files changed

+280
-78
lines changed

9 files changed

+280
-78
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
from openai.types.chat import ChatCompletionMessageParam
2-
from mito_ai.models import SmartDebugMetadata, MessageType
3-
from mito_ai.prompt_builders.smart_debug_prompt import create_error_prompt, remove_inner_thoughts_from_message
2+
from mito_ai.models import AgentResponse, AgentSmartDebugMetadata, MessageType, ResponseFormatInfo
3+
from mito_ai.prompt_builders.agent_smart_debug_prompt import create_agent_smart_debug_prompt
44
from mito_ai.providers import OpenAIProvider
55
from mito_ai.message_history import GlobalMessageHistory
66
from mito_ai.completion_handlers.completion_handler import CompletionHandler
77
from mito_ai.completion_handlers.open_ai_models import MESSAGE_TYPE_TO_MODEL
88
from mito_ai.completion_handlers.utils import append_agent_system_message
9+
10+
911
__all__ = ["get_agent_auto_error_fixup_completion"]
1012

11-
class AgentAutoErrorFixupHandler(CompletionHandler[SmartDebugMetadata]):
13+
class AgentAutoErrorFixupHandler(CompletionHandler[AgentSmartDebugMetadata]):
1214
"""Handler for smart debug completions."""
1315

1416
@staticmethod
1517
async def get_completion(
16-
metadata: SmartDebugMetadata,
18+
metadata: AgentSmartDebugMetadata,
1719
provider: OpenAIProvider,
1820
message_history: GlobalMessageHistory
1921
) -> str:
@@ -22,40 +24,31 @@ async def get_completion(
2224
# Add the system message if it doens't alredy exist
2325
await append_agent_system_message(message_history, provider)
2426

25-
error_message = metadata.errorMessage
26-
active_cell_code = metadata.activeCellCode or ''
27-
variables = metadata.variables or []
28-
files = metadata.files or []
29-
3027
# Create the prompt
31-
prompt = create_error_prompt(
32-
error_message,
33-
active_cell_code,
34-
variables,
35-
files
36-
)
28+
prompt = create_agent_smart_debug_prompt(metadata)
3729

3830
# Add the prompt to the message history
3931
new_ai_optimized_message: ChatCompletionMessageParam = {"role": "user", "content": prompt}
40-
new_display_optimized_message: ChatCompletionMessageParam = {"role": "user", "content": error_message}
32+
new_display_optimized_message: ChatCompletionMessageParam = {"role": "user", "content": metadata.errorMessage}
4133
await message_history.append_message(new_ai_optimized_message, new_display_optimized_message, provider)
4234

4335
# Get the completion
4436
completion = await provider.request_completions(
4537
messages=message_history.ai_optimized_history,
4638
model=MESSAGE_TYPE_TO_MODEL[MessageType.AGENT_AUTO_ERROR_FIXUP],
39+
response_format_info=ResponseFormatInfo(
40+
name='agent_response',
41+
format=AgentResponse
42+
),
4743
message_type=MessageType.AGENT_AUTO_ERROR_FIXUP
4844
)
4945

50-
# Process the completion to remove inner thoughts
51-
display_completion = remove_inner_thoughts_from_message(completion)
52-
5346
# Add the response to message history
5447
ai_response_message: ChatCompletionMessageParam = {"role": "assistant", "content": completion}
55-
display_response_message: ChatCompletionMessageParam = {"role": "assistant", "content": display_completion}
48+
display_response_message: ChatCompletionMessageParam = {"role": "assistant", "content": completion}
5649
await message_history.append_message(ai_response_message, display_response_message, provider)
5750

58-
return display_completion
51+
return completion
5952

6053
# Use the static method directly
6154
get_agent_auto_error_fixup_completion = AgentAutoErrorFixupHandler.get_completion

mito-ai/mito_ai/completion_handlers/completion_handler.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from typing import Protocol, TypeVar
22
from abc import abstractmethod, ABCMeta
3-
from mito_ai.models import ChatMessageMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, InlineCompleterMetadata
3+
from mito_ai.models import ChatMessageMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, InlineCompleterMetadata, AgentSmartDebugMetadata
44
from mito_ai.providers import OpenAIProvider
55
from mito_ai.message_history import GlobalMessageHistory
66

7-
T = TypeVar('T', ChatMessageMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, InlineCompleterMetadata, contravariant=True)
7+
T = TypeVar('T', ChatMessageMetadata, SmartDebugMetadata, CodeExplainMetadata, AgentExecutionMetadata, AgentSmartDebugMetadata, InlineCompleterMetadata, contravariant=True)
88

99
class CompletionHandler(Protocol[T], metaclass=ABCMeta):
1010
"""Protocol defining the interface for completion handlers.

mito-ai/mito_ai/handlers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from mito_ai.message_history import GlobalMessageHistory
1515
from mito_ai.logger import get_logger
1616
from mito_ai.models import (
17+
AgentSmartDebugMetadata,
1718
CompletionError,
1819
CompletionItem,
1920
CompletionReply,
@@ -195,7 +196,7 @@ async def on_message(self, message: str) -> None: # type: ignore
195196
agent_execution_metadata = AgentExecutionMetadata(**metadata_dict)
196197
completion = await get_agent_execution_completion(agent_execution_metadata, self._llm, message_history)
197198
elif type == MessageType.AGENT_AUTO_ERROR_FIXUP:
198-
agent_auto_error_fixup_metadata = SmartDebugMetadata(**metadata_dict)
199+
agent_auto_error_fixup_metadata = AgentSmartDebugMetadata(**metadata_dict)
199200
completion = await get_agent_auto_error_fixup_completion(agent_auto_error_fixup_metadata, self._llm, message_history)
200201
elif type == MessageType.INLINE_COMPLETION:
201202
inline_completer_metadata = InlineCompleterMetadata(**metadata_dict)

mito-ai/mito_ai/models.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
ThreadID = NewType('ThreadID', str)
1010

1111
@dataclass(frozen=True)
12-
class AIOptimizedCells():
12+
class AIOptimizedCell():
1313
cell_type: str
1414
id: str
1515
code: str
@@ -66,7 +66,16 @@ class ChatMessageMetadata():
6666
class AgentExecutionMetadata():
6767
promptType: Literal['agent:execution']
6868
input: str
69-
aiOptimizedCells: List[AIOptimizedCells]
69+
aiOptimizedCells: List[AIOptimizedCell]
70+
variables: Optional[List[str]] = None
71+
files: Optional[List[str]] = None
72+
73+
@dataclass(frozen=True)
74+
class AgentSmartDebugMetadata():
75+
promptType: Literal['agent:autoErrorFixup']
76+
aiOptimizedCells: List[AIOptimizedCell]
77+
errorMessage: str
78+
error_message_producing_code_cell_id: str
7079
variables: Optional[List[str]] = None
7180
files: Optional[List[str]] = None
7281

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
from typing import List
2+
from mito_ai.models import AgentSmartDebugMetadata
3+
4+
# TODO:
5+
# 1. In the future, it might make sense to pass the previous CELL_UPDATE to this prompt?
6+
# 2. In the future, we should let the agent fix up the error by updating a different cell. This is sometimes a better solution.
7+
# However, to do this, we then need to know which code cells to run in order to validate the update is correct! If the error was
8+
# produced by code cell 3, and the agent corrects the source of the error in code cell 2, we then need to run cell 2 and 3 to validate
9+
# the cell update worked properly. This could be many cells if there are intermediate cells. It might require something like a dependency
10+
# graph of cells that we calculate ourselves, not relying on the AI.
11+
12+
def create_agent_smart_debug_prompt(md: AgentSmartDebugMetadata) -> str:
13+
variables_str = '\n'.join([f"{variable}" for variable in md.variables or []])
14+
files_str = '\n'.join([f"{file}" for file in md.files or []])
15+
ai_optimized_cells_str = '\n'.join([f"{cell}" for cell in md.aiOptimizedCells or []])
16+
17+
return f"""I just applied and executed the CELL_UPDATE that you just shared with me, but it errored. Below I am sharing with you a strategy for how I want you to resolve this error and information about the actual error that occured.
18+
19+
Use this strategy for this message only. After this message, continue using the original set of instructions that I provided you.
20+
21+
It is very important that When fixing this error, you do not change the original intent of the code cell.
22+
23+
To fix this error, take the following approach:
24+
Step 1: ERROR ANALYSIS: Analyze the error message to identify why the code cell errored.
25+
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
26+
Step 3: ERROR CORRECTION: Respond with a new CELL_UPDATE that is applied to the same cell as the erroring CELL_UPDATE.
27+
28+
<Instructions for each Phase />
29+
30+
ERROR ANALYSIS:
31+
32+
- Identify error type (Syntax, Runtime, Logic).
33+
- Use the defined variables and Jupyter Notebook to understand the error.
34+
- Consider kernel state and execution order
35+
36+
INTENT PRESERVATION:
37+
38+
- Try to understand the user's intent using the defined variables and the Jupyter Notebook
39+
40+
ERROR CORRECTION:
41+
42+
- Return the full, updated version of cell {md.error_message_producing_code_cell_id} with the error fixed and a short explanation of the error.
43+
- 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.
44+
- Propose a solution that fixes the error and does not change the user's intent.
45+
- Make the solution as simple as possible.
46+
- Reuse as much of the existing code as possible.
47+
- DO NOT ADD TEMPORARY COMMENTS like '# Fixed the typo here' or '# Added this line to fix the error'
48+
49+
<Example>
50+
51+
<Input>
52+
53+
Files in the current directory:
54+
file_name: sales.csv
55+
56+
Jupyter Notebook:
57+
[
58+
{{
59+
cell_type: 'markdown'
60+
id: '9e38c62b-38f8-457d-bb8d-28bfc52edf2c'
61+
code: \"\"\"# Transaction Analysis \"\"\"
62+
}},
63+
{{
64+
cell_type: 'code'
65+
id: 'adslkaf-jf73-l8xn-92j7-kjd8kdcnd2kso'
66+
code: \"\"\" 'df' = pd.DataFrame({{
67+
'order_id': [1, 2, 3, 4],
68+
'date': ['Mar 7, 2025', 'Sep 24, 2024', '25 June, 2024', 'June 29, 2024'],
69+
'amount': [100, 150, 299, 99]
70+
}})
71+
}},
72+
{{
73+
cell_type: 'code'
74+
id: 'c68fdf19-db8c-46dd-926f-d90ad35bb3bc'
75+
code: \"\"\"df['date'] = pd.to_datetime(df['date'])\"\"\"
76+
}},
77+
]
78+
79+
Defined Variables:
80+
{{
81+
'df': pd.DataFrame({{
82+
'order_id': [1, 2, 3, 4],
83+
'date': ['Mar 7, 2025', 'Sep 24, 2024', '25 June, 2024', 'June 29, 2024'],
84+
'amount': [100, 150, 299, 99]
85+
}})
86+
}}
87+
88+
Cell ID of the Error Producing Code Cell:
89+
'c68fdf19-db8c-46dd-926f-d90ad35bb3bc'
90+
91+
Error Traceback:
92+
Cell In[27], line 1
93+
----> 1 df['date'] = pd.to_datetime(df['date'])
94+
95+
ValueError: time data "25 June, 2024" doesn't match format "%b %d, %Y", at position 2. You might want to try:
96+
- passing `format` if your strings have a consistent format;
97+
- passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format;
98+
- passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.
99+
100+
101+
</ Input>
102+
103+
< Your Thinking >
104+
105+
ERROR ANALYSIS
106+
This is a ValueError caused by applying the wrong format to a specific date string. Because it was triggered at position 2, the first date string must have successfully converted. By looking at the defined variables, I can see that first date string is in the format "Mar 7, 2025", but the third date string is in the format "25 June, 2024". Those dates are not in the same format, so the conversion failed.
107+
108+
INTENT PRESERVATION:
109+
User is trying to convert the date column to a datetime object even though the dates are not in the same starting format.
110+
111+
</ Your Thinking >
112+
113+
<Output>
114+
115+
116+
{{
117+
is_finished: false,
118+
cell_update: {{
119+
type: 'modification'
120+
id: 'c68fdf19-db8c-46dd-926f-d90ad35bb3bc'
121+
code: "def parse_date(date_str):\n formats = ['%b %d, %Y', '%d %B, %Y']\n\n for fmt in formats:\n try:\n return pd.to_datetime(date_str, format=fmt)\n except ValueError:\n # Try next format\n continue\n\n # If not format worked, return Not a Time\n return pd.NaT\n\ndf['date'] = df['date'].apply(lambda x: parse_date(x))"
122+
}}
123+
}}
124+
125+
</Output>
126+
127+
</Example>
128+
129+
Files in the current directory:
130+
{files_str}
131+
132+
Jupyter Notebook:
133+
{ai_optimized_cells_str}
134+
135+
Defined Variables:
136+
{variables_str}
137+
138+
Cell ID of the Error Producing Code Cell:
139+
{md.error_message_producing_code_cell_id}
140+
141+
Error Traceback:
142+
{md.errorMessage}
143+
"""

mito-ai/src/Extensions/AiChat/ChatHistoryManager.tsx

+29-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import OpenAI from "openai";
22
import { IContextManager } from "../ContextManager/ContextManagerPlugin";
33
import { INotebookTracker } from '@jupyterlab/notebook';
44
import { getActiveCellCode, getActiveCellID, getAIOptimizedCells, getCellCodeByID } from "../../utils/notebook";
5-
import { AgentResponse, IAgentExecutionMetadata, IChatMessageMetadata, ICodeExplainMetadata, ISmartDebugMetadata } from "../../utils/websocket/models";
5+
import { AgentResponse, IAgentExecutionMetadata, IAgentSmartDebugMetadata, IChatMessageMetadata, ICodeExplainMetadata, ISmartDebugMetadata } from "../../utils/websocket/models";
66
import { addMarkdownCodeFormatting } from "../../utils/strings";
77

88
export type PromptType =
@@ -145,7 +145,7 @@ export class ChatHistoryManager {
145145
}
146146

147147

148-
addDebugErrorMessage(errorMessage: string, promptType: PromptType): ISmartDebugMetadata {
148+
addSmartDebugMessage(errorMessage: string): ISmartDebugMetadata {
149149

150150
const activeCellID = getActiveCellID(this.notebookTracker)
151151
const activeCellCode = getCellCodeByID(this.notebookTracker, activeCellID)
@@ -163,13 +163,39 @@ export class ChatHistoryManager {
163163
message: getDisplayedOptimizedUserMessage(errorMessage, activeCellCode),
164164
type: 'openai message',
165165
codeCellID: activeCellID,
166-
promptType: promptType
166+
promptType: 'smartDebug'
167167
}
168168
);
169169

170170
return smartDebugMetadata
171171
}
172172

173+
addAgentSmartDebugMessage(errorMessage: string): IAgentSmartDebugMetadata {
174+
175+
const activeCellID = getActiveCellID(this.notebookTracker)
176+
const activeCellCode = getActiveCellCode(this.notebookTracker)
177+
178+
const agentSmartDebugMetadata: IAgentSmartDebugMetadata = {
179+
promptType: 'agent:autoErrorFixup',
180+
aiOptimizedCells: getAIOptimizedCells(this.notebookTracker),
181+
variables: this.contextManager.variables,
182+
files: this.contextManager.files,
183+
errorMessage: errorMessage,
184+
error_message_producing_code_cell_id: activeCellID || ''
185+
}
186+
187+
this.displayOptimizedChatHistory.push(
188+
{
189+
message: getDisplayedOptimizedUserMessage(errorMessage, activeCellCode),
190+
type: 'openai message',
191+
codeCellID: activeCellID,
192+
promptType: 'agent:autoErrorFixup'
193+
}
194+
);
195+
196+
return agentSmartDebugMetadata
197+
}
198+
173199
addExplainCodeMessage(): ICodeExplainMetadata {
174200

175201
const activeCellID = getActiveCellID(this.notebookTracker)

0 commit comments

Comments
 (0)