mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
Improve stop button message for better user experience (#9860)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
parent
238ae611f6
commit
1c66347803
@ -583,7 +583,8 @@ export enum I18nKey {
|
||||
BITBUCKET$TOKEN_LINK_TEXT = "BITBUCKET$TOKEN_LINK_TEXT",
|
||||
BITBUCKET$INSTRUCTIONS_LINK_TEXT = "BITBUCKET$INSTRUCTIONS_LINK_TEXT",
|
||||
GITLAB$OR_SEE = "GITLAB$OR_SEE",
|
||||
AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED = "AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED",
|
||||
AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_STOPPED = "AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_STOPPED",
|
||||
AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_ERROR = "AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_ERROR",
|
||||
DIFF_VIEWER$LOADING = "DIFF_VIEWER$LOADING",
|
||||
DIFF_VIEWER$GETTING_LATEST_CHANGES = "DIFF_VIEWER$GETTING_LATEST_CHANGES",
|
||||
DIFF_VIEWER$NOT_A_GIT_REPO = "DIFF_VIEWER$NOT_A_GIT_REPO",
|
||||
|
||||
@ -9327,21 +9327,37 @@
|
||||
"de": "oder siehe",
|
||||
"uk": "або перегляньте"
|
||||
},
|
||||
"AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED": {
|
||||
"en": "The action has not been executed. This may have occurred because the user pressed the stop button, or because the runtime system crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.",
|
||||
"ja": "アクションは実行されていません。これはユーザーが停止ボタンを押したか、リソース制約によりランタイムシステムがクラッシュして再起動したことが原因かもしれません。以前に確立されたシステム状態、依存関係、または環境変数は失われている可能性があります。",
|
||||
"zh-CN": "该操作尚未执行。这可能是因为用户按下了停止按钮,或者因为运行时系统由于资源限制而崩溃并重新启动。任何先前建立的系统状态、依赖项或环境变量可能已丢失。",
|
||||
"zh-TW": "該操作尚未執行。這可能是因為用戶按下了停止按鈕,或者因為運行時系統由於資源限制而崩潰並重新啟動。任何先前建立的系統狀態、依賴項或環境變數可能已丟失。",
|
||||
"ko-KR": "작업이 실행되지 않았습니다. 이는 사용자가 중지 버튼을 눌렀거나 리소스 제약으로 인해 런타임 시스템이 충돌하고 재시작되었기 때문일 수 있습니다. 이전에 설정된 시스템 상태, 종속성 또는 환경 변수가 손실되었을 수 있습니다.",
|
||||
"no": "Handlingen har ikke blitt utført. Dette kan ha skjedd fordi brukeren trykket på stoppknappen, eller fordi kjøretidssystemet krasjet og startet på nytt på grunn av ressursbegrensninger. Enhver tidligere etablert systemtilstand, avhengigheter eller miljøvariabler kan ha gått tapt.",
|
||||
"it": "L'azione non è stata eseguita. Ciò potrebbe essere accaduto perché l'utente ha premuto il pulsante di arresto, o perché il sistema di runtime si è arrestato in modo anomalo e riavviato a causa di vincoli di risorse. Qualsiasi stato di sistema, dipendenza o variabile d'ambiente precedentemente stabilito potrebbe essere andato perso.",
|
||||
"pt": "A ação não foi executada. Isso pode ter ocorrido porque o usuário pressionou o botão de parar, ou porque o sistema de tempo de execução travou e reiniciou devido a restrições de recursos. Qualquer estado do sistema, dependências ou variáveis de ambiente estabelecidos anteriormente podem ter sido perdidos.",
|
||||
"es": "La acción no se ha ejecutado. Esto puede haber ocurrido porque el usuario presionó el botón de detener, o porque el sistema de tiempo de ejecución se bloqueó y reinició debido a restricciones de recursos. Cualquier estado del sistema, dependencias o variables de entorno establecidos previamente pueden haberse perdido.",
|
||||
"ar": "لم يتم تنفيذ الإجراء. قد يكون هذا حدث لأن المستخدم ضغط على زر التوقف، أو لأن نظام التشغيل تعطل وأعيد تشغيله بسبب قيود الموارد. قد تكون أي حالة نظام أو تبعيات أو متغيرات بيئية تم إنشاؤها مسبقًا قد فُقدت.",
|
||||
"fr": "L'action n'a pas été exécutée. Cela peut s'être produit parce que l'utilisateur a appuyé sur le bouton d'arrêt, ou parce que le système d'exécution s'est planté et a redémarré en raison de contraintes de ressources. Tout état du système, dépendances ou variables d'environnement précédemment établis peuvent avoir été perdus.",
|
||||
"tr": "Eylem yürütülmedi. Bu, kullanıcının durdurma düğmesine basması veya çalışma zamanı sisteminin kaynak kısıtlamaları nedeniyle çökmesi ve yeniden başlaması nedeniyle olmuş olabilir. Daha önce kurulmuş olan herhangi bir sistem durumu, bağımlılıklar veya ortam değişkenleri kaybolmuş olabilir.",
|
||||
"de": "Die Aktion wurde nicht ausgeführt. Dies kann passiert sein, weil der Benutzer die Stopp-Taste gedrückt hat oder weil das Laufzeitsystem aufgrund von Ressourcenbeschränkungen abgestürzt und neu gestartet wurde. Alle zuvor eingerichteten Systemzustände, Abhängigkeiten oder Umgebungsvariablen sind möglicherweise verloren gegangen.",
|
||||
"uk": "Дію не виконано. Можливо, це сталося через натискання користувачем кнопки зупинки або через збій та перезапуск системи виконання через обмеження ресурсів. Можливо, було втрачено будь-який раніше встановлений стан системи, залежності або змінні середовища."
|
||||
"AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_STOPPED": {
|
||||
"en": "Stop button pressed. The action has not been executed.",
|
||||
"ja": "停止ボタンが押されました。アクションは実行されていません。",
|
||||
"zh-CN": "按下了停止按钮。操作尚未执行。",
|
||||
"zh-TW": "按下了停止按鈕。操作尚未執行。",
|
||||
"ko-KR": "중지 버튼이 눌렸습니다. 작업이 실행되지 않았습니다.",
|
||||
"no": "Stoppknappen ble trykket. Handlingen har ikke blitt utført.",
|
||||
"it": "Pulsante di arresto premuto. L'azione non è stata eseguita.",
|
||||
"pt": "Botão de parar pressionado. A ação não foi executada.",
|
||||
"es": "Botón de detener presionado. La acción no se ha ejecutado.",
|
||||
"ar": "تم الضغط على زر التوقف. لم يتم تنفيذ الإجراء.",
|
||||
"fr": "Bouton d'arrêt appuyé. L'action n'a pas été exécutée.",
|
||||
"tr": "Durdurma düğmesine basıldı. Eylem yürütülmedi.",
|
||||
"de": "Stopp-Taste gedrückt. Die Aktion wurde nicht ausgeführt.",
|
||||
"uk": "Натиснуто кнопку зупинки. Дію не виконано."
|
||||
},
|
||||
"AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_ERROR": {
|
||||
"en": "The action has not been executed due to a runtime error. The runtime system may have crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.",
|
||||
"ja": "ランタイムエラーによりアクションは実行されていません。リソース制約によりランタイムシステムがクラッシュして再起動した可能性があります。以前に確立されたシステム状態、依存関係、または環境変数は失われている可能性があります。",
|
||||
"zh-CN": "由于运行时错误,该操作尚未执行。运行时系统可能由于资源限制而崩溃并重新启动。任何先前建立的系统状态、依赖项或环境变量可能已丢失。",
|
||||
"zh-TW": "由於運行時錯誤,該操作尚未執行。運行時系統可能由於資源限制而崩潰並重新啟動。任何先前建立的系統狀態、依賴項或環境變數可能已丟失。",
|
||||
"ko-KR": "런타임 오류로 인해 작업이 실행되지 않았습니다. 리소스 제약으로 인해 런타임 시스템이 충돌하고 재시작되었을 수 있습니다. 이전에 설정된 시스템 상태, 종속성 또는 환경 변수가 손실되었을 수 있습니다.",
|
||||
"no": "Handlingen har ikke blitt utført på grunn av en kjøretidsfeil. Kjøretidssystemet kan ha krasjet og startet på nytt på grunn av ressursbegrensninger. Enhver tidligere etablert systemtilstand, avhengigheter eller miljøvariabler kan ha gått tapt.",
|
||||
"it": "L'azione non è stata eseguita a causa di un errore di runtime. Il sistema di runtime potrebbe essere andato in crash e riavviato a causa di vincoli di risorse. Qualsiasi stato di sistema, dipendenza o variabile d'ambiente precedentemente stabilito potrebbe essere andato perso.",
|
||||
"pt": "A ação não foi executada devido a um erro de tempo de execução. O sistema de tempo de execução pode ter travado e reiniciado devido a restrições de recursos. Qualquer estado do sistema, dependências ou variáveis de ambiente estabelecidos anteriormente podem ter sido perdidos.",
|
||||
"es": "La acción no se ha ejecutado debido a un error de tiempo de ejecución. El sistema de tiempo de ejecución puede haberse bloqueado y reiniciado debido a restricciones de recursos. Cualquier estado del sistema, dependencias o variables de entorno establecidos previamente pueden haberse perdido.",
|
||||
"ar": "لم يتم تنفيذ الإجراء بسبب خطأ في وقت التشغيل. قد يكون نظام وقت التشغيل قد تعطل وأعيد تشغيله بسبب قيود الموارد. قد تكون أي حالة نظام أو تبعيات أو متغيرات بيئية تم إنشاؤها مسبقًا قد فُقدت.",
|
||||
"fr": "L'action n'a pas été exécutée en raison d'une erreur d'exécution. Le système d'exécution peut s'être planté et avoir redémarré en raison de contraintes de ressources. Tout état du système, dépendances ou variables d'environnement précédemment établis peuvent avoir été perdus.",
|
||||
"tr": "Çalışma zamanı hatası nedeniyle eylem yürütülmedi. Çalışma zamanı sistemi kaynak kısıtlamaları nedeniyle çökmüş ve yeniden başlamış olabilir. Daha önce kurulmuş olan herhangi bir sistem durumu, bağımlılıklar veya ortam değişkenleri kaybolmuş olabilir.",
|
||||
"de": "Die Aktion wurde aufgrund eines Laufzeitfehlers nicht ausgeführt. Das Laufzeitsystem ist möglicherweise aufgrund von Ressourcenbeschränkungen abgestürzt und neu gestartet worden. Alle zuvor eingerichteten Systemzustände, Abhängigkeiten oder Umgebungsvariablen sind möglicherweise verloren gegangen.",
|
||||
"uk": "Дію не виконано через помилку виконання. Система виконання могла зазнати збою та перезапуститися через обмеження ресурсів. Можливо, було втрачено будь-який раніше встановлений стан системи, залежності або змінні середовища."
|
||||
},
|
||||
"DIFF_VIEWER$LOADING": {
|
||||
"en": "Loading changes...",
|
||||
|
||||
@ -82,8 +82,12 @@ from openhands.storage.files import FileStore
|
||||
TRAFFIC_CONTROL_REMINDER = (
|
||||
"Please click on resume button if you'd like to continue, or start a new task."
|
||||
)
|
||||
ERROR_ACTION_NOT_EXECUTED_ID = 'AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED'
|
||||
ERROR_ACTION_NOT_EXECUTED = 'The action has not been executed. This may have occurred because the user pressed the stop button, or because the runtime system crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.'
|
||||
ERROR_ACTION_NOT_EXECUTED_STOPPED_ID = 'AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_STOPPED'
|
||||
ERROR_ACTION_NOT_EXECUTED_ERROR_ID = 'AGENT_ERROR$ERROR_ACTION_NOT_EXECUTED_ERROR'
|
||||
ERROR_ACTION_NOT_EXECUTED_STOPPED = (
|
||||
'Stop button pressed. The action has not been executed.'
|
||||
)
|
||||
ERROR_ACTION_NOT_EXECUTED_ERROR = 'The action has not been executed due to a runtime error. The runtime system may have crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.'
|
||||
|
||||
|
||||
class AgentController:
|
||||
@ -552,9 +556,17 @@ class AgentController:
|
||||
|
||||
# make a new ErrorObservation with the tool call metadata
|
||||
if not found_observation:
|
||||
# Use different messages and IDs based on whether the agent was stopped by user or due to error
|
||||
if self.state.agent_state == AgentState.STOPPED:
|
||||
error_content = ERROR_ACTION_NOT_EXECUTED_STOPPED
|
||||
error_id = ERROR_ACTION_NOT_EXECUTED_STOPPED_ID
|
||||
else: # AgentState.ERROR
|
||||
error_content = ERROR_ACTION_NOT_EXECUTED_ERROR
|
||||
error_id = ERROR_ACTION_NOT_EXECUTED_ERROR_ID
|
||||
|
||||
obs = ErrorObservation(
|
||||
content=ERROR_ACTION_NOT_EXECUTED,
|
||||
error_id=ERROR_ACTION_NOT_EXECUTED_ID,
|
||||
content=error_content,
|
||||
error_id=error_id,
|
||||
)
|
||||
obs.tool_call_metadata = self._pending_action.tool_call_metadata
|
||||
obs._cause = self._pending_action.id # type: ignore[attr-defined]
|
||||
@ -580,14 +592,17 @@ class AgentController:
|
||||
if new_state == self.state.agent_state:
|
||||
return
|
||||
|
||||
# Store old state for control limits check
|
||||
old_state = self.state.agent_state
|
||||
|
||||
# Update agent state BEFORE calling _reset() so _reset() sees the correct state
|
||||
self.state.agent_state = new_state
|
||||
|
||||
if new_state in (AgentState.STOPPED, AgentState.ERROR):
|
||||
self._reset()
|
||||
|
||||
# User is allowing to check control limits and expand them if applicable
|
||||
if (
|
||||
self.state.agent_state == AgentState.ERROR
|
||||
and new_state == AgentState.RUNNING
|
||||
):
|
||||
if old_state == AgentState.ERROR and new_state == AgentState.RUNNING:
|
||||
self.state_tracker.maybe_increase_control_flags_limits(self.headless_mode)
|
||||
|
||||
if self._pending_action is not None and (
|
||||
@ -603,8 +618,6 @@ class AgentController:
|
||||
self._pending_action._id = None # type: ignore[attr-defined]
|
||||
self.event_stream.add_event(self._pending_action, EventSource.AGENT)
|
||||
|
||||
self.state.agent_state = new_state
|
||||
|
||||
# Create observation with reason field if it's an error state
|
||||
reason = ''
|
||||
if new_state == AgentState.ERROR:
|
||||
|
||||
@ -603,7 +603,7 @@ async def test_reset_with_pending_action_no_observation(mock_agent, mock_event_s
|
||||
assert isinstance(error_obs, ErrorObservation)
|
||||
assert (
|
||||
error_obs.content
|
||||
== 'The action has not been executed. This may have occurred because the user pressed the stop button, or because the runtime system crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.'
|
||||
== 'The action has not been executed due to a runtime error. The runtime system may have crashed and restarted due to resource constraints. Any previously established system state, dependencies, or environment variables may have been lost.'
|
||||
)
|
||||
assert error_obs.tool_call_metadata == pending_action.tool_call_metadata
|
||||
assert error_obs._cause == pending_action.id
|
||||
@ -617,6 +617,53 @@ async def test_reset_with_pending_action_no_observation(mock_agent, mock_event_s
|
||||
await controller.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reset_with_pending_action_stopped_state(mock_agent, mock_event_stream):
|
||||
"""Test reset() when there's a pending action and agent state is STOPPED."""
|
||||
controller = AgentController(
|
||||
agent=mock_agent,
|
||||
event_stream=mock_event_stream,
|
||||
iteration_delta=10,
|
||||
sid='test',
|
||||
confirmation_mode=False,
|
||||
headless_mode=True,
|
||||
)
|
||||
|
||||
mock_event_stream.add_event.assert_called_once() # add SystemMessageAction
|
||||
mock_event_stream.add_event.reset_mock()
|
||||
|
||||
# Create a pending action with tool call metadata
|
||||
pending_action = CmdRunAction(command='test')
|
||||
pending_action.tool_call_metadata = {
|
||||
'function': 'test_function',
|
||||
'args': {'arg1': 'value1'},
|
||||
}
|
||||
controller._pending_action = pending_action
|
||||
|
||||
# Set agent state to STOPPED
|
||||
controller.state.agent_state = AgentState.STOPPED
|
||||
|
||||
# Call reset
|
||||
controller._reset()
|
||||
|
||||
# Verify that an ErrorObservation was added to the event stream
|
||||
mock_event_stream.add_event.assert_called_once()
|
||||
args, kwargs = mock_event_stream.add_event.call_args
|
||||
error_obs, source = args
|
||||
assert isinstance(error_obs, ErrorObservation)
|
||||
assert error_obs.content == 'Stop button pressed. The action has not been executed.'
|
||||
assert error_obs.tool_call_metadata == pending_action.tool_call_metadata
|
||||
assert error_obs._cause == pending_action.id
|
||||
assert source == EventSource.AGENT
|
||||
|
||||
# Verify that pending action was reset
|
||||
assert controller._pending_action is None
|
||||
|
||||
# Verify that agent.reset() was called
|
||||
mock_agent.reset.assert_called_once()
|
||||
await controller.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reset_with_pending_action_existing_observation(
|
||||
mock_agent, mock_event_stream
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user