From 97a45ff66a9345c87f6bdb7fc8abcf0a168ad371 Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Mon, 10 Aug 2026 11:15:56 -0700 Subject: [PATCH 1/4] feat(code): warn above configurable session cost threshold --- libs/code/deepagents_code/app.py | 61 +++++++++++++++++++ libs/code/deepagents_code/config_manifest.py | 16 +++++ .../tests/unit_tests/test_resume_state.py | 37 +++++++++++ 3 files changed, 114 insertions(+) diff --git a/libs/code/deepagents_code/app.py b/libs/code/deepagents_code/app.py index d422cd9e4a9..65ca81ab16a 100644 --- a/libs/code/deepagents_code/app.py +++ b/libs/code/deepagents_code/app.py @@ -1390,6 +1390,37 @@ def _load_cursor_style_preference() -> CursorStyle: return cast("CursorStyle", value) +def _load_session_cost_warning_threshold() -> float: + """Resolve the estimated-cost threshold for the one-time session warning. + + Returns: + The configured threshold in US dollars. Zero or negative disables the + warning. + """ + from deepagents_code.config_manifest import ( + SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, + get_option, + load_config_toml, + resolve_scalar, + ) + + option = get_option("warnings.session_cost_threshold_usd") + if option is None: + logger.warning( + "Unknown config option %r; using the default session cost threshold", + "warnings.session_cost_threshold_usd", + ) + return SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT + value, _ = resolve_scalar(option, toml_data=load_config_toml()) + if not isinstance(value, float) or not math.isfinite(value): + logger.warning( + "Invalid session cost warning threshold %r; using the default", + value, + ) + return SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT + return value + + def _load_terminal_progress_preference() -> bool: """Load the `OSC 9;4` progress preference from `~/.deepagents/config.toml`. @@ -3937,6 +3968,14 @@ def __init__( estimates here. """ + self._session_cost_warning_threshold_usd = ( + _load_session_cost_warning_threshold() + ) + """Configured soft limit for the active thread's estimated cost.""" + + self._session_cost_warning_shown = False + """Whether the active thread has already crossed its cost soft limit.""" + self._provisional_cost_usd: float = 0.0 """Streamed spend the graph has not reported a total for yet. @@ -7619,6 +7658,27 @@ def _set_session_cost( self._session_cost_usd = _coerce_session_cost_usd(cost_usd) self._provisional_cost_usd = 0.0 self._refresh_session_cost_display() + self._maybe_warn_session_cost() + + def _maybe_warn_session_cost(self) -> None: + """Warn once when the active thread crosses its configured cost soft limit.""" + threshold = self._session_cost_warning_threshold_usd + if ( + self._session_cost_warning_shown + or threshold <= 0 + or self._session_cost_usd <= threshold + ): + return + self._session_cost_warning_shown = True + self.notify( + f"Estimated session cost is {format_cost(self._session_cost_usd)}, above " + f"the configured {format_cost(threshold)} threshold. Consider /compact " + "to reduce context usage or /clear to start fresh.", + title="Session cost warning", + severity="warning", + timeout=12, + markup=False, + ) @property def _displayed_cost_usd(self) -> float: @@ -7648,6 +7708,7 @@ def _reset_thread_usage( has_restored_model_usage or self._thread_restored_cost_usd > 0 ) self._thread_has_completed_turn = False + self._session_cost_warning_shown = False self._set_session_cost(self._thread_restored_cost_usd) def _mark_thread_turn_completed(self) -> None: diff --git a/libs/code/deepagents_code/config_manifest.py b/libs/code/deepagents_code/config_manifest.py index f662d66b0e6..7590d1a6968 100644 --- a/libs/code/deepagents_code/config_manifest.py +++ b/libs/code/deepagents_code/config_manifest.py @@ -114,6 +114,12 @@ Zero or negative disables the suggestion. """ +SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT = 50.0 +"""Estimated thread cost above which the user is warned once per session. + +Zero or negative disables the warning. +""" + LANGSMITH_PROJECT_DEFAULT = "deepagents-code" """Project agent traces fall back to when no project env var is set. @@ -1540,6 +1546,16 @@ def _credential_options() -> tuple[ConfigOption, ...]: toml_keys=("threads", "columns"), ), # --- Warnings ------------------------------------------------------ + ConfigOption( + key="warnings.session_cost_threshold_usd", + group="Warnings", + summary=( + "Warn once when estimated thread cost exceeds this USD amount (0 disables)." + ), + kind=OptionKind.FLOAT, + default=SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, + toml_keys=("warnings", "session_cost_threshold_usd"), + ), ConfigOption( key="warnings.suppress", group="Warnings", diff --git a/libs/code/tests/unit_tests/test_resume_state.py b/libs/code/tests/unit_tests/test_resume_state.py index f87ae8ff215..456fa4ad964 100644 --- a/libs/code/tests/unit_tests/test_resume_state.py +++ b/libs/code/tests/unit_tests/test_resume_state.py @@ -340,6 +340,43 @@ def test_server_total_replaces_the_displayed_value(self) -> None: assert app._session_cost_usd == pytest.approx(1.25) assert app._displayed_cost_usd == pytest.approx(1.25) + def test_cost_threshold_warns_once_per_thread( + self, monkeypatch: pytest.MonkeyPatch + ) -> None: + from deepagents_code import config_manifest + + monkeypatch.setattr( + config_manifest, + "load_config_toml", + lambda: {"warnings": {"session_cost_threshold_usd": 1.0}}, + ) + app = DeepAgentsApp() + notifications: list[tuple[str, dict[str, Any]]] = [] + monkeypatch.setattr( + app, + "notify", + lambda message, **kwargs: notifications.append((message, kwargs)), + ) + + app._set_session_cost(1.0) + app._set_session_cost(1.01) + app._set_session_cost(2.0) + + assert len(notifications) == 1 + message, kwargs = notifications[0] + assert "$1.01" in message + assert "/compact" in message + assert "/clear" in message + assert kwargs == { + "title": "Session cost warning", + "severity": "warning", + "timeout": 12, + "markup": False, + } + + app._reset_thread_usage(1.5) + assert len(notifications) == 2 + def test_streamed_estimate_shows_ahead_of_the_server_total(self) -> None: """Spend the graph has not reported yet still moves the display.""" app = DeepAgentsApp() From 032df87a67eccefc00f84660a99195c749ff4668 Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Mon, 10 Aug 2026 11:24:45 -0700 Subject: [PATCH 2/4] fix(code): suggest canonical `/offload` command --- libs/code/deepagents_code/app.py | 2 +- libs/code/tests/unit_tests/test_resume_state.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/code/deepagents_code/app.py b/libs/code/deepagents_code/app.py index 65ca81ab16a..6d19c10e23b 100644 --- a/libs/code/deepagents_code/app.py +++ b/libs/code/deepagents_code/app.py @@ -7672,7 +7672,7 @@ def _maybe_warn_session_cost(self) -> None: self._session_cost_warning_shown = True self.notify( f"Estimated session cost is {format_cost(self._session_cost_usd)}, above " - f"the configured {format_cost(threshold)} threshold. Consider /compact " + f"the configured {format_cost(threshold)} threshold. Consider /offload " "to reduce context usage or /clear to start fresh.", title="Session cost warning", severity="warning", diff --git a/libs/code/tests/unit_tests/test_resume_state.py b/libs/code/tests/unit_tests/test_resume_state.py index 456fa4ad964..17e7ca77aa8 100644 --- a/libs/code/tests/unit_tests/test_resume_state.py +++ b/libs/code/tests/unit_tests/test_resume_state.py @@ -365,7 +365,7 @@ def test_cost_threshold_warns_once_per_thread( assert len(notifications) == 1 message, kwargs = notifications[0] assert "$1.01" in message - assert "/compact" in message + assert "/offload" in message assert "/clear" in message assert kwargs == { "title": "Session cost warning", From 3bb8a7e2bee52d5d8a8fa70975b0f4930c708196 Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Mon, 10 Aug 2026 11:36:15 -0700 Subject: [PATCH 3/4] refactor(code): simplify session cost warning --- libs/code/deepagents_code/app.py | 84 ++++++++----------- libs/code/deepagents_code/config_manifest.py | 9 +- .../tests/unit_tests/test_resume_state.py | 22 ++--- 3 files changed, 41 insertions(+), 74 deletions(-) diff --git a/libs/code/deepagents_code/app.py b/libs/code/deepagents_code/app.py index 6d19c10e23b..9a6596ca492 100644 --- a/libs/code/deepagents_code/app.py +++ b/libs/code/deepagents_code/app.py @@ -1390,37 +1390,6 @@ def _load_cursor_style_preference() -> CursorStyle: return cast("CursorStyle", value) -def _load_session_cost_warning_threshold() -> float: - """Resolve the estimated-cost threshold for the one-time session warning. - - Returns: - The configured threshold in US dollars. Zero or negative disables the - warning. - """ - from deepagents_code.config_manifest import ( - SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, - get_option, - load_config_toml, - resolve_scalar, - ) - - option = get_option("warnings.session_cost_threshold_usd") - if option is None: - logger.warning( - "Unknown config option %r; using the default session cost threshold", - "warnings.session_cost_threshold_usd", - ) - return SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT - value, _ = resolve_scalar(option, toml_data=load_config_toml()) - if not isinstance(value, float) or not math.isfinite(value): - logger.warning( - "Invalid session cost warning threshold %r; using the default", - value, - ) - return SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT - return value - - def _load_terminal_progress_preference() -> bool: """Load the `OSC 9;4` progress preference from `~/.deepagents/config.toml`. @@ -3968,9 +3937,28 @@ def __init__( estimates here. """ - self._session_cost_warning_threshold_usd = ( - _load_session_cost_warning_threshold() + from deepagents_code.config_manifest import ( + SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, + get_option, + load_config_toml, + resolve_scalar, ) + + cost_warning_option = get_option("warnings.session_cost_threshold_usd") + cost_warning_threshold: object = SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT + if cost_warning_option is not None: + cost_warning_threshold, _ = resolve_scalar( + cost_warning_option, toml_data=load_config_toml() + ) + if not isinstance(cost_warning_threshold, float) or not math.isfinite( + cost_warning_threshold + ): + logger.warning( + "Invalid session cost warning threshold %r; using the default", + cost_warning_threshold, + ) + cost_warning_threshold = SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT + self._session_cost_warning_threshold_usd = cost_warning_threshold """Configured soft limit for the active thread's estimated cost.""" self._session_cost_warning_shown = False @@ -7658,27 +7646,21 @@ def _set_session_cost( self._session_cost_usd = _coerce_session_cost_usd(cost_usd) self._provisional_cost_usd = 0.0 self._refresh_session_cost_display() - self._maybe_warn_session_cost() - - def _maybe_warn_session_cost(self) -> None: - """Warn once when the active thread crosses its configured cost soft limit.""" threshold = self._session_cost_warning_threshold_usd if ( - self._session_cost_warning_shown - or threshold <= 0 - or self._session_cost_usd <= threshold + not self._session_cost_warning_shown + and 0 < threshold < self._session_cost_usd ): - return - self._session_cost_warning_shown = True - self.notify( - f"Estimated session cost is {format_cost(self._session_cost_usd)}, above " - f"the configured {format_cost(threshold)} threshold. Consider /offload " - "to reduce context usage or /clear to start fresh.", - title="Session cost warning", - severity="warning", - timeout=12, - markup=False, - ) + self._session_cost_warning_shown = True + self.notify( + f"Estimated session cost is {format_cost(self._session_cost_usd)}, " + f"above the configured {format_cost(threshold)} threshold. Consider " + "/offload to reduce context usage or /clear to start fresh.", + title="Session cost warning", + severity="warning", + timeout=12, + markup=False, + ) @property def _displayed_cost_usd(self) -> float: diff --git a/libs/code/deepagents_code/config_manifest.py b/libs/code/deepagents_code/config_manifest.py index 7590d1a6968..fb33477cb44 100644 --- a/libs/code/deepagents_code/config_manifest.py +++ b/libs/code/deepagents_code/config_manifest.py @@ -115,10 +115,7 @@ """ SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT = 50.0 -"""Estimated thread cost above which the user is warned once per session. - -Zero or negative disables the warning. -""" +"""Default warning threshold in USD; zero or negative disables the warning.""" LANGSMITH_PROJECT_DEFAULT = "deepagents-code" """Project agent traces fall back to when no project env var is set. @@ -1549,9 +1546,7 @@ def _credential_options() -> tuple[ConfigOption, ...]: ConfigOption( key="warnings.session_cost_threshold_usd", group="Warnings", - summary=( - "Warn once when estimated thread cost exceeds this USD amount (0 disables)." - ), + summary="Warn above this estimated thread cost in USD (0 disables).", kind=OptionKind.FLOAT, default=SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, toml_keys=("warnings", "session_cost_threshold_usd"), diff --git a/libs/code/tests/unit_tests/test_resume_state.py b/libs/code/tests/unit_tests/test_resume_state.py index 17e7ca77aa8..83abd98b151 100644 --- a/libs/code/tests/unit_tests/test_resume_state.py +++ b/libs/code/tests/unit_tests/test_resume_state.py @@ -343,19 +343,16 @@ def test_server_total_replaces_the_displayed_value(self) -> None: def test_cost_threshold_warns_once_per_thread( self, monkeypatch: pytest.MonkeyPatch ) -> None: - from deepagents_code import config_manifest - monkeypatch.setattr( - config_manifest, - "load_config_toml", + "deepagents_code.config_manifest.load_config_toml", lambda: {"warnings": {"session_cost_threshold_usd": 1.0}}, ) app = DeepAgentsApp() - notifications: list[tuple[str, dict[str, Any]]] = [] + notifications: list[str] = [] monkeypatch.setattr( app, "notify", - lambda message, **kwargs: notifications.append((message, kwargs)), + lambda message, **_: notifications.append(message), ) app._set_session_cost(1.0) @@ -363,16 +360,9 @@ def test_cost_threshold_warns_once_per_thread( app._set_session_cost(2.0) assert len(notifications) == 1 - message, kwargs = notifications[0] - assert "$1.01" in message - assert "/offload" in message - assert "/clear" in message - assert kwargs == { - "title": "Session cost warning", - "severity": "warning", - "timeout": 12, - "markup": False, - } + assert "$1.01" in notifications[0] + assert "/offload" in notifications[0] + assert "/clear" in notifications[0] app._reset_thread_usage(1.5) assert len(notifications) == 2 From 82ed413179e0831d706dd102e6a1a5e80c007b7f Mon Sep 17 00:00:00 2001 From: Johannes du Plessis Date: Mon, 10 Aug 2026 11:37:53 -0700 Subject: [PATCH 4/4] refactor(code): preserve cost warning summary --- libs/code/deepagents_code/config_manifest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/code/deepagents_code/config_manifest.py b/libs/code/deepagents_code/config_manifest.py index fb33477cb44..ac5135db8ae 100644 --- a/libs/code/deepagents_code/config_manifest.py +++ b/libs/code/deepagents_code/config_manifest.py @@ -1546,7 +1546,9 @@ def _credential_options() -> tuple[ConfigOption, ...]: ConfigOption( key="warnings.session_cost_threshold_usd", group="Warnings", - summary="Warn above this estimated thread cost in USD (0 disables).", + summary=( + "Warn once when estimated thread cost exceeds this USD amount (0 disables)." + ), kind=OptionKind.FLOAT, default=SESSION_COST_WARNING_THRESHOLD_USD_DEFAULT, toml_keys=("warnings", "session_cost_threshold_usd"),