From 61ba4370f102256c905ba8aaa2c44d9c995740f2 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Thu, 12 Mar 2026 21:01:55 +0000 Subject: [PATCH] fix(cli): address review findings on session commands - Replace # type: ignore[assignment] with cast() (F1/L1) - Fix show command format check to include COLOR variant (H1/F3) - Remove unnecessary AttributeError from all 7 catch tuples (F2) - Add CHANGELOG.md entry for session DI fix (F4) Refs: #554, #570 --- CHANGELOG.md | 13 +++++++++++++ src/cleveragents/cli/commands/session.py | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index df5b21249..4634d031a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ## Unreleased +- Fixed `agents session list`, `agents session create`, and other session + subcommands raising `AttributeError: 'DynamicContainer' object has no + attribute 'db'` after `agents init`. Root cause: `_get_session_service()` + called `container.db()` but no `db` provider existed. Added a + `session_service` DI provider in `container.py` that builds the engine, + sessionmaker, and auto-committing repositories. Rewrote + `_get_session_service()` to resolve via the container with module-level + caching. Added `auto_commit` parameter to `SessionRepository` and + `SessionMessageRepository` to prevent resource leaks in CLI context while + preserving Unit-of-Work semantics. Unified error handling across all 7 + session subcommands. Includes Behave BDD regression scenarios, Robot + Framework integration smoke tests, and structlog isolation for parallel + test execution. (#554, #570, #680) - Added TDD-style failing Behave BDD tests for the session list DI container missing `db` provider bug. Three scenarios exercise `session list`, `_get_session_service()`, and `session list --format json` through the real diff --git a/src/cleveragents/cli/commands/session.py b/src/cleveragents/cli/commands/session.py index 81870c99a..b85980535 100644 --- a/src/cleveragents/cli/commands/session.py +++ b/src/cleveragents/cli/commands/session.py @@ -14,7 +14,7 @@ import logging import sys from collections import OrderedDict from pathlib import Path -from typing import Annotated, Any +from typing import Annotated, Any, cast import typer from rich.console import Console @@ -60,7 +60,7 @@ def _get_session_service() -> SessionService: from cleveragents.application.container import get_container container = get_container() - svc: SessionService = container.session_service() # type: ignore[assignment] + svc = cast(SessionService, container.session_service()) _service = svc return _service @@ -153,7 +153,7 @@ def create( except SessionNotFoundError as exc: console.print(f"[red]Error:[/red] {exc}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session create failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -181,7 +181,7 @@ def list_sessions( try: service = _get_session_service() sessions = service.list() - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session list failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -255,7 +255,7 @@ def show( session = service.get(session_id) data = session.as_cli_dict() - if fmt != OutputFormat.RICH.value: + if fmt not in (OutputFormat.RICH.value, OutputFormat.COLOR.value): typer.echo(format_output(dict(data), fmt)) return @@ -327,7 +327,7 @@ def show( except SessionNotFoundError as exc: console.print(f"[red]Session not found:[/red] {session_id}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session show failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -373,7 +373,7 @@ def delete( except SessionNotFoundError as exc: console.print(f"[red]Session not found:[/red] {session_id}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session delete failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -432,7 +432,7 @@ def export_session( except SessionExportError as exc: console.print(f"[red]Export error:[/red] {exc}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session export failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -483,7 +483,7 @@ def import_session( except SessionImportError as exc: console.print(f"[red]Import error:[/red] {exc}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session import failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n" @@ -558,7 +558,7 @@ def tell( except SessionNotFoundError as exc: console.print(f"[red]Session not found:[/red] {session_id}") raise typer.Exit(1) from exc - except (DatabaseError, AttributeError) as exc: + except DatabaseError as exc: _log.debug("session tell failed", exc_info=True) console.print( f"[red]Error:[/red] Database unavailable: {exc}\n"