From d69e5a44681c05ad994280a8231876db30079686 Mon Sep 17 00:00:00 2001 From: meetp06 <65815199+meetp06@users.noreply.github.com> Date: Mon, 13 Jul 2026 16:14:15 -0700 Subject: [PATCH 1/2] fix(ai): raise task error/warning history cap from 50 to a named constant (#1414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live task status kept only the most recent 50 error and 50 warning messages (`task_engine.py`, hardcoded `[-50:]`), so on a run with many diagnostics the earlier errors were dropped before anyone could read them — the exact symptom called out in #1414 ("error/warning arrays capped at 50"). Replace the two magic `50`s with a single named constant, `CONST_STATUS_HISTORY_LIMIT` (1000), alongside the other `CONST_*` limits, and update the `TASK_STATUS` field descriptions in the Python SDK to match. This retains far more history in memory while keeping a bound so a pathological run cannot grow the buffers without limit. Scope: this addresses only the in-memory cap. Durable run-history persistence (the other half of #1414 — JSONL sink, downloadable trace, survive disconnect) is a larger change and is intentionally left as separate follow-up. Co-Authored-By: Claude Opus 4.8 --- packages/ai/src/ai/constants.py | 1 + packages/ai/src/ai/modules/task/task_engine.py | 9 +++++---- packages/client-python/src/rocketride/types/task.py | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) 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/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') From c50bdcf50072fc4daf7a849ec84b48ebadfee8e8 Mon Sep 17 00:00:00 2001 From: meetp06 <65815199+meetp06@users.noreply.github.com> Date: Mon, 13 Jul 2026 19:29:25 -0700 Subject: [PATCH 2/2] test(ai): make status-history cap test track CONST_STATUS_HISTORY_LIMIT test_update_status_errors_buffer_trims_to_50 hardcoded the old 50 cap and broke when the limit was raised. Seed CONST_STATUS_HISTORY_LIMIT entries and assert the buffer trims to that constant, so the test tracks the configured limit instead of a magic number. Rename accordingly and drop the stale "50" wording from the warning test. Co-Authored-By: Claude Opus 4.8 --- packages/ai/tests/ai/modules/task/test_task_engine.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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,