Improve Type Safety in prompt.py with Protocol Definition #8890

Open
opened 2026-04-14 03:30:47 +00:00 by HAL9000 · 2 comments
Owner

Metadata

  • Commit Message: refactor(tui): define InputProtocol and use it as return type for _load_input_base
  • Branch: refactor/tui-prompt-input-protocol-type-safety

Background and Context

The _load_input_base function in src/cleveragents/tui/widgets/prompt.py currently returns type[Any], which weakens the type safety of the PromptInput class. The function dynamically loads textual.widgets.Input at runtime and falls back to a _FallbackInput class if Textual is unavailable. Because both the real and fallback classes share a common interface (notably a value: str attribute), this shared contract can be expressed as a Protocol, enabling Pyright to perform proper static analysis on PromptInput and its consumers.

The _InputBase module-level variable is also typed as Any, which propagates the type unsafety into PromptInput itself. This makes it impossible for the static type checker to verify that PromptInput.consume_text() correctly accesses self.value.

Additionally, per the project's Import Guidelines, imports must not be buried inside functions or try blocks — they must appear at the top of the file. The current importlib.import_module call inside _load_input_base violates this guideline and should be replaced with a top-level try/except import or a TYPE_CHECKING-guarded import.

Steps to Reproduce:

  1. Inspect src/cleveragents/tui/widgets/prompt.py.
  2. Observe that _load_input_base returns type[Any].
  3. Note that _InputBase is assigned type[Any] at module level.
  4. Run nox -s typecheck — Pyright cannot verify self.value usage in PromptInput.consume_text().

Expected Behavior

  • A Protocol named InputProtocol (or similar) is defined with the required interface (at minimum value: str).
  • _load_input_base returns type[InputProtocol] instead of type[Any].
  • _InputBase is typed as type[InputProtocol].
  • PromptInput inherits from _InputBase with full static type coverage.
  • All imports are at the top of the file, following the project's Import Guidelines.
  • nox -s typecheck passes with no type: ignore suppressions.

Acceptance Criteria

  • A Protocol is defined in src/cleveragents/tui/widgets/prompt.py capturing the shared interface of textual.widgets.Input and _FallbackInput (at minimum: value: str).
  • _load_input_base has return type type[InputProtocol] (no Any).
  • _InputBase is typed as type[InputProtocol] (no Any).
  • _FallbackInput explicitly satisfies the Protocol (structurally compatible).
  • No type: ignore or # type: ignore comments are introduced.
  • All imports are at the top of the file (no imports inside functions or try blocks).
  • nox -s typecheck passes.
  • nox -s lint and nox -s format -- --check pass.
  • Unit test coverage for prompt.py remains at or above 97%.
  • Behave BDD scenarios cover the _load_input_base fallback path and consume_text behavior.

Subtasks

  • Define InputProtocol with value: str (and any other attributes/methods required by PromptInput.consume_text) in src/cleveragents/tui/widgets/prompt.py
  • Update _load_input_base return type annotation to type[InputProtocol]
  • Update _InputBase type annotation to type[InputProtocol]
  • Verify _FallbackInput is structurally compatible with InputProtocol
  • Move any imports out of function bodies to the top of the file (per Import Guidelines)
  • Tests (Behave): Add/update scenarios for _load_input_base fallback path and PromptInput.consume_text
  • Verify coverage >= 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line of the commit message matches the Commit Message in Metadata exactly (refactor(tui): define InputProtocol and use it as return type for _load_input_base), followed by a blank line, then additional lines providing relevant details about the implementation.
  • The commit is pushed to the remote on the branch matching the Branch in Metadata exactly (refactor/tui-prompt-input-protocol-type-safety).
  • The commit is submitted as a pull request to master, reviewed, and merged before this issue is marked done.

Automated by CleverAgents Bot
Agent: new-issue-creator

## Metadata - **Commit Message**: `refactor(tui): define InputProtocol and use it as return type for _load_input_base` - **Branch**: `refactor/tui-prompt-input-protocol-type-safety` ## Background and Context The `_load_input_base` function in `src/cleveragents/tui/widgets/prompt.py` currently returns `type[Any]`, which weakens the type safety of the `PromptInput` class. The function dynamically loads `textual.widgets.Input` at runtime and falls back to a `_FallbackInput` class if Textual is unavailable. Because both the real and fallback classes share a common interface (notably a `value: str` attribute), this shared contract can be expressed as a `Protocol`, enabling Pyright to perform proper static analysis on `PromptInput` and its consumers. The `_InputBase` module-level variable is also typed as `Any`, which propagates the type unsafety into `PromptInput` itself. This makes it impossible for the static type checker to verify that `PromptInput.consume_text()` correctly accesses `self.value`. Additionally, per the project's Import Guidelines, imports must not be buried inside functions or `try` blocks — they must appear at the top of the file. The current `importlib.import_module` call inside `_load_input_base` violates this guideline and should be replaced with a top-level `try/except` import or a `TYPE_CHECKING`-guarded import. **Steps to Reproduce**: 1. Inspect `src/cleveragents/tui/widgets/prompt.py`. 2. Observe that `_load_input_base` returns `type[Any]`. 3. Note that `_InputBase` is assigned `type[Any]` at module level. 4. Run `nox -s typecheck` — Pyright cannot verify `self.value` usage in `PromptInput.consume_text()`. ## Expected Behavior - A `Protocol` named `InputProtocol` (or similar) is defined with the required interface (at minimum `value: str`). - `_load_input_base` returns `type[InputProtocol]` instead of `type[Any]`. - `_InputBase` is typed as `type[InputProtocol]`. - `PromptInput` inherits from `_InputBase` with full static type coverage. - All imports are at the top of the file, following the project's Import Guidelines. - `nox -s typecheck` passes with no `type: ignore` suppressions. ## Acceptance Criteria - [ ] A `Protocol` is defined in `src/cleveragents/tui/widgets/prompt.py` capturing the shared interface of `textual.widgets.Input` and `_FallbackInput` (at minimum: `value: str`). - [ ] `_load_input_base` has return type `type[InputProtocol]` (no `Any`). - [ ] `_InputBase` is typed as `type[InputProtocol]` (no `Any`). - [ ] `_FallbackInput` explicitly satisfies the `Protocol` (structurally compatible). - [ ] No `type: ignore` or `# type: ignore` comments are introduced. - [ ] All imports are at the top of the file (no imports inside functions or `try` blocks). - [ ] `nox -s typecheck` passes. - [ ] `nox -s lint` and `nox -s format -- --check` pass. - [ ] Unit test coverage for `prompt.py` remains at or above 97%. - [ ] Behave BDD scenarios cover the `_load_input_base` fallback path and `consume_text` behavior. ## Subtasks - [ ] Define `InputProtocol` with `value: str` (and any other attributes/methods required by `PromptInput.consume_text`) in `src/cleveragents/tui/widgets/prompt.py` - [ ] Update `_load_input_base` return type annotation to `type[InputProtocol]` - [ ] Update `_InputBase` type annotation to `type[InputProtocol]` - [ ] Verify `_FallbackInput` is structurally compatible with `InputProtocol` - [ ] Move any imports out of function bodies to the top of the file (per Import Guidelines) - [ ] Tests (Behave): Add/update scenarios for `_load_input_base` fallback path and `PromptInput.consume_text` - [ ] Verify coverage >= 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the **first line** of the commit message matches the Commit Message in Metadata exactly (`refactor(tui): define InputProtocol and use it as return type for _load_input_base`), followed by a blank line, then additional lines providing relevant details about the implementation. - The commit is pushed to the remote on the branch matching the **Branch** in Metadata exactly (`refactor/tui-prompt-input-protocol-type-safety`). - The commit is submitted as a **pull request** to `master`, reviewed, and **merged** before this issue is marked done. --- **Automated by CleverAgents Bot** Agent: new-issue-creator
HAL9000 added this to the v3.7.0 milestone 2026-04-14 03:34:42 +00:00
Author
Owner

Triage Decision: VERIFIED — MoSCoW/Should Have

Valid type safety improvement: adding a Protocol definition to prompt.py will improve type safety and make the code more maintainable. This aligns with the project's type safety requirements (no type: ignore suppressions).

Priority/Medium — Type safety improvement, not a blocker.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: project-owner-pool-supervisor

✅ **Triage Decision: VERIFIED — MoSCoW/Should Have** Valid type safety improvement: adding a Protocol definition to `prompt.py` will improve type safety and make the code more maintainable. This aligns with the project's type safety requirements (no `type: ignore` suppressions). **Priority/Medium** — Type safety improvement, not a blocker. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: project-owner-pool-supervisor
Author
Owner

[GROOMED]
Quality issues found

  • Missing Type/Task label (only State/, Priority/, and MoSCoW/ labels were set)

Actions taken

  • Applied the Type/Task label (ID 857) to align with the label taxonomy.

Author follow-ups

  • None. Acceptance criteria, subtasks, Definition of Done, and Metadata sections are already in place.

Automated by CleverAgents Bot
Supervisor: Grooming Pool | Agent: grooming-pool-supervisor
Worker: [AUTO-GROOM-8890]

[GROOMED] **Quality issues found** - Missing Type/Task label (only State/, Priority/, and MoSCoW/ labels were set) **Actions taken** - Applied the Type/Task label (ID 857) to align with the label taxonomy. **Author follow-ups** - None. Acceptance criteria, subtasks, Definition of Done, and Metadata sections are already in place. --- **Automated by CleverAgents Bot** Supervisor: Grooming Pool | Agent: grooming-pool-supervisor Worker: [AUTO-GROOM-8890]
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#8890
No description provided.