diff --git a/packages/ai/src/ai/constants.py b/packages/ai/src/ai/constants.py index 3d725acc5..1e39de24b 100644 --- a/packages/ai/src/ai/constants.py +++ b/packages/ai/src/ai/constants.py @@ -52,6 +52,7 @@ CONST_READY_POLL_INTERVAL = 0.250 # seconds between readiness checks CONST_SUBPROCESS_BUFFER_LIMIT = 16 * 1024 * 1024 # bytes for subprocess stdin/stdout/stderr buffers (16MB) CONST_STATUS_UPDATE_CANCEL_TIMEOUT = 2.0 # seconds to wait for status update task cancellation +CONST_STATUS_HISTORY_LIMIT = 1000 # max error/warning messages retained per task in memory (was 50; see #1414) CONST_DEFAULT_TTL = 15 * 60 # default time-to-live for idle tasks in seconds (15 minutes) CONST_TTL_CHECK = 60 # check for tasks to kill every 60 seconds diff --git a/packages/ai/src/ai/modules/task/task_engine.py b/packages/ai/src/ai/modules/task/task_engine.py index 94a764965..2c860789d 100644 --- a/packages/ai/src/ai/modules/task/task_engine.py +++ b/packages/ai/src/ai/modules/task/task_engine.py @@ -50,6 +50,7 @@ CONST_READY_POLL_INTERVAL, CONST_SUBPROCESS_BUFFER_LIMIT, CONST_STATUS_UPDATE_CANCEL_TIMEOUT, + CONST_STATUS_HISTORY_LIMIT, ) from ai import CONST_AI_NODE_SCRIPT from ai.common.dap import DAPBase, DAPClient, TransportWebSocket @@ -940,16 +941,16 @@ def _update_status(self, message: Dict[str, Any]) -> None: error_message = body.get('message', '') self._status.errors.append(error_message) - if len(self._status.errors) > 50: - self._status.errors = self._status.errors[-50:] + if len(self._status.errors) > CONST_STATUS_HISTORY_LIMIT: + self._status.errors = self._status.errors[-CONST_STATUS_HISTORY_LIMIT:] # Handle warning messages with buffer management elif event_type == 'apaevt_status_warning': warning_message = body.get('message', '') self._status.warnings.append(warning_message) - if len(self._status.warnings) > 50: - self._status.warnings = self._status.warnings[-50:] + if len(self._status.warnings) > CONST_STATUS_HISTORY_LIMIT: + self._status.warnings = self._status.warnings[-CONST_STATUS_HISTORY_LIMIT:] # Handle download progress elif event_type == 'apaevt_status_download': diff --git a/packages/ai/tests/ai/modules/task/test_task_engine.py b/packages/ai/tests/ai/modules/task/test_task_engine.py index dfeee06a1..3dd0df9d9 100644 --- a/packages/ai/tests/ai/modules/task/test_task_engine.py +++ b/packages/ai/tests/ai/modules/task/test_task_engine.py @@ -33,6 +33,7 @@ import pytest +from ai.constants import CONST_STATUS_HISTORY_LIMIT from ai.modules.task.task_engine import Task @@ -470,10 +471,10 @@ def test_update_status_error_event_appends_to_errors(): assert t._status.errors == ['disk full'] -def test_update_status_errors_buffer_trims_to_50(): - """Error buffer keeps only the most recent 50 entries.""" +def test_update_status_errors_buffer_trims_to_limit(): + """Error buffer keeps only the most recent CONST_STATUS_HISTORY_LIMIT entries.""" t = _task(status=_make_status_for_update()) - t._status.errors = [f'err-{i}' for i in range(50)] + t._status.errors = [f'err-{i}' for i in range(CONST_STATUS_HISTORY_LIMIT)] Task._update_status( t, { @@ -481,13 +482,13 @@ def test_update_status_errors_buffer_trims_to_50(): 'body': {'message': 'err-new'}, }, ) - assert len(t._status.errors) == 50 + assert len(t._status.errors) == CONST_STATUS_HISTORY_LIMIT assert t._status.errors[-1] == 'err-new' assert 'err-0' not in t._status.errors # oldest evicted def test_update_status_warning_event_appends_and_trims(): - """An ``apaevt_status_warning`` event appends to warnings with the same 50-cap.""" + """An ``apaevt_status_warning`` event appends to warnings with the same history cap.""" t = _task(status=_make_status_for_update()) Task._update_status( t, diff --git a/packages/client-python/src/rocketride/types/task.py b/packages/client-python/src/rocketride/types/task.py index 09ce29b2d..9d7716aee 100644 --- a/packages/client-python/src/rocketride/types/task.py +++ b/packages/client-python/src/rocketride/types/task.py @@ -360,10 +360,12 @@ class TASK_STATUS(BaseModel): # Error and Warning Management with History warnings: List[str] = Field( - default_factory=list, description='Warning message history (limited to 50 recent entries)' + default_factory=list, description='Warning message history (limited to 1000 recent entries)' ) - errors: List[str] = Field(default_factory=list, description='Error message history (limited to 50 recent entries)') + errors: List[str] = Field( + default_factory=list, description='Error message history (limited to 1000 recent entries)' + ) # Current Processing Context currentObject: str = Field(default='', description='Name/identifier of the item currently being processed')