docs: map types and I/O data interfaces for issue #441 - #478
Conversation
Field-level trace of the five data boundaries (tool args, session persistence, agent messages, runtime state, UI display shapes), the concrete shapes flowing through each Any annotation, dead-code inventory, and the target type design. Includes an HTML visualization of the same map. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U3DHf5FbGZiDLMSWpq53gK
Removes symbols with zero callers, verified by trace (see docs/architecture/types-and-io-interfaces.md): - types/base.py: AgentConfig, ErrorContext, UpdateOperation, Validator, ValidationResult, CommandResult, CommandArgs, InputSessions, FileDiff, DiffHunk, DiffLine dead aliases - types/callbacks.py: UICallback, UIInputCallback, AsyncFunc, AsyncToolFunc, AsyncVoidFunc dead aliases - utils/messaging/adapter.py: to_canonical_list, from_canonical, from_canonical_list (zero call sites) - tools/utils/ripgrep.py: RipgrepExecutor and RipgrepMetrics (only get_ripgrep_binary_path is consumed) - core/session/state.py: vestigial SessionState fields (spinner, current_task, input_sessions, undo_initialized) and the unwired recursive-execution cluster (task_hierarchy, recursive_context_stack, depth counters, iteration budgets, push/pop/reset methods); the sole external caller (/clear) only reset fields nothing ever writes - core/types/state.py: matching protocol methods - core/types/state_structures.py: vestigial RuntimeState.streaming_panel Also refreshes stale module docs that described the removed canonical message layer. mypy clean, 324 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U3DHf5FbGZiDLMSWpq53gK
…dDicts (issue #441) Replaces hand-written dict[str, Any] with the existing ToolArgs alias (= tinyagent JsonObject) across the tool rendering pipeline: RenderFunc, the renderer protocol/base, all six tool renderers, tool_panel / tool_panel_smart, ToolDisplayData.arguments, and ToolCallPartProtocol.args. Adds types/tool_args.py declaring each renderer's de-facto argument schema (BashArgs, ReadFileArgs, WriteFileArgs, WebFetchArgs, HashlineEditArgs; total=False since model output is untrusted). parse_result narrows ToolArgs to its tool's schema at the boundary, so key typos and wrong value types are now caught by mypy. The stricter signature immediately surfaced one loose call site (shell_runner building a bash args dict), now annotated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U3DHf5FbGZiDLMSWpq53gK
- types-and-io-interfaces.md: record executed progress (dead-code deletion 5ce24c4, tool-args boundary f0fe551), mark B1 done, move removed symbols to past tense, and consolidate remaining work into one table. Drop the HTML visualization from the repo. - modules/types/types.md: remove stale canonical.py/CanonicalMessage and LspSettings references, document tool_args.py and the ToolArgs narrowing pattern, note UsageCost/UsageMetrics live in __init__.py. - modules/core/core.md: SessionState no longer tracks recursion state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U3DHf5FbGZiDLMSWpq53gK
📝 WalkthroughWalkthroughThe PR simplifies session and messaging APIs, removes ripgrep execution utilities, introduces typed tool-argument schemas, and updates UI renderer contracts and callers to use those schemas. ChangesSession state simplification
Typed tool argument contracts
Ripgrep utility reduction
Canonical messaging API reduction
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 7 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (7 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/tunacode/core/session/state.py (1)
111-113: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
reset_session()should restore loaded config and the model context window (src/tunacode/core/session/state.py:111-113)
StateManager.__init__()calls_load_user_configuration(), butreset_session()replaces the session with a bareSessionState(). That drops the merged user config and leavesconversation.max_tokensat its default, so the next run can use stale/default settings. Reuse the init path here, or preserveuser_config/current_modelwhen resetting runtime state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/tunacode/core/session/state.py` around lines 111 - 113, Update StateManager.reset_session() so resetting runtime state preserves the configuration loaded by StateManager.__init__(), including user_config and current_model, and restores conversation.max_tokens from the active model context window. Reuse the existing initialization/configuration path where appropriate instead of replacing the session with an unconfigured bare SessionState.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/tunacode/types/callbacks.py`:
- Line 38: Update the callback type definitions around the args annotation to
remove imports of ToolArgs, ToolName, and ToolResult from tunacode.types.base,
keeping src/tunacode/types self-contained with only stdlib/typing dependencies.
Define the necessary shared aliases locally or move them to an allowed shared
location, then update the callback annotations to use those aliases without
violating the types-layer import gate.
In `@src/tunacode/ui/renderers/tools/discover.py`:
- Line 164: Update DiscoverRenderer.parse_result to explicitly mark the
intentionally unused args parameter, such as by assigning it to the project’s
standard unused-variable convention, while preserving the existing result
parsing behavior; do not introduce a DiscoverArgs schema.
In `@src/tunacode/ui/shell_runner.py`:
- Around line 144-145: Update the type annotation for the bash tool argument
literals in the shell runner to use BashArgs instead of the broader ToolArgs.
Apply this at both annotated occurrences, including the literal consumed by
render_bash/BashRenderer, and adjust the import accordingly so mypy validates
the expected BashArgs keys.
---
Outside diff comments:
In `@src/tunacode/core/session/state.py`:
- Around line 111-113: Update StateManager.reset_session() so resetting runtime
state preserves the configuration loaded by StateManager.__init__(), including
user_config and current_model, and restores conversation.max_tokens from the
active model context window. Reuse the existing initialization/configuration
path where appropriate instead of replacing the session with an unconfigured
bare SessionState.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 4fd5e9f5-be0f-4a56-a8e0-0ab1a7f17430
⛔ Files ignored due to path filters (4)
docs/architecture/types-and-io-interfaces.mdis excluded by!**/docs/**,!**/*.mddocs/modules/core/core.mdis excluded by!**/docs/**,!**/*.mddocs/modules/types/types.mdis excluded by!**/docs/**,!**/*.mddocs/modules/utils/utils.mdis excluded by!**/docs/**,!**/*.md
📒 Files selected for processing (20)
src/tunacode/core/session/state.pysrc/tunacode/core/types/state.pysrc/tunacode/core/types/state_structures.pysrc/tunacode/tools/utils/ripgrep.pysrc/tunacode/types/__init__.pysrc/tunacode/types/base.pysrc/tunacode/types/callbacks.pysrc/tunacode/types/tool_args.pysrc/tunacode/ui/commands/clear.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/write_file.pysrc/tunacode/ui/shell_runner.pysrc/tunacode/utils/messaging/__init__.pysrc/tunacode/utils/messaging/adapter.py
💤 Files with no reviewable changes (5)
- src/tunacode/core/types/state.py
- src/tunacode/ui/commands/clear.py
- src/tunacode/utils/messaging/init.py
- src/tunacode/tools/utils/ripgrep.py
- src/tunacode/utils/messaging/adapter.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py
📄 CodeRabbit inference engine (Custom checks)
**/*.py: Enforce dependency direction: ui → core → tools → utils/types. Flag violations where core/ imports from ui/, tools/ imports from ui/, tools/ imports from core/, or types/ imports from anything except stdlib/typing
In agent/orchestration code, verify exception handlers clean up state: flagexcept (UserAbortError, CancelledError)patterns that exist without corresponding cleanup like_remove_dangling_tool_calls()or state rollback. State mutations (messages.append, session modifications) followed by await/function calls that could raise must be cleaned up in except blocks
Check for shallow copy followed by nested dict mutation: flag.copy()on dicts that contain nested dicts/lists. Usedeepcopy()instead or use dictionary spreading syntax to avoid mutating original objects
Enforce error handling principle: 'Fail fast, fail loud. No silent fallbacks.' Flagexcept: pass,except Exception: pass, empty except blocks, catching broad exceptions without re-raising or logging, and returning None/[]/{} sentinel values instead of raising exceptions for invalid inputs
**/*.py: Use Python 3.11 or newer.
Do not introduce new file-specific exemptions to the>600line rule; fix the enforcement path or split the code instead.
Files:
src/tunacode/ui/shell_runner.pysrc/tunacode/types/tool_args.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/core/types/state_structures.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/types/base.pysrc/tunacode/ui/renderers/tools/write_file.pysrc/tunacode/core/session/state.pysrc/tunacode/types/callbacks.pysrc/tunacode/types/__init__.py
src/tunacode/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
src/tunacode/**/*.py: Keep application code under the primarysrc/tunacode/package and preserve its documented package structure.
Preserve the dependency directiontypes -> utils -> infrastructure -> configuration -> tools -> core -> ui; do not add imports across forbidden layers.
Follow the repository's documented import ordering for shared modules and layered modules.
Do not add TunaCode-owned message-contract wrappers around tinyagent message types; use tinyagent models directly in memory and keep dict payloads at real boundaries.
Prefer small, scoped, minimal, and targeted edits; follow existing nearby patterns, including command and test naming.
Files:
src/tunacode/ui/shell_runner.pysrc/tunacode/types/tool_args.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/core/types/state_structures.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/types/base.pysrc/tunacode/ui/renderers/tools/write_file.pysrc/tunacode/core/session/state.pysrc/tunacode/types/callbacks.pysrc/tunacode/types/__init__.py
src/tunacode/ui/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Keep Rich default/ANSI color handling local to TunaCode; preserve the startup/theme stability behavior involving
render_safety.pyand built-in theme wrapping inconstants.py.
Files:
src/tunacode/ui/shell_runner.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/ui/renderers/tools/write_file.py
⚙️ CodeRabbit configuration file
src/tunacode/ui/**/*.py: UI layer rules:
DEPENDENCY DIRECTION: ui/ can import from core/, tools/, utils/, types/
- core/ MUST NOT import from ui/ (check for violations)
GATE 5 - Indirection Requires Verification:
- If using
expand=True, verify actual rendered width- Panel widths should be explicit, not delegated
Command implementations:
- Must handle errors gracefully
- Must not corrupt session state (see PR
#264/update crash)
Files:
src/tunacode/ui/shell_runner.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/ui/renderers/tools/write_file.py
**/*
📄 CodeRabbit inference engine (AGENTS.md)
**/*: Before any Git operation, readdocs/git/practices.mdin the current session.
Never delete or clean untracked files or directories without explicit user confirmation; pause and ask if unknown files appear during checks.
During commit-time check failures, apply only trivial lint-only fixes; otherwise stop and request user instruction rather than making architectural or refactoring changes.
Do not edit unrelated local changes unless they are within the task scope.
Avoid adding empty directories or__init__.py-only directories.
Run validation commands before handoff when touching architecture, dependencies, or shared packages.
Files:
src/tunacode/ui/shell_runner.pysrc/tunacode/types/tool_args.pysrc/tunacode/ui/renderers/tools/bash.pysrc/tunacode/ui/renderers/tools/web_fetch.pysrc/tunacode/ui/renderers/tools/read_file.pysrc/tunacode/ui/renderers/tools/discover.pysrc/tunacode/core/types/state_structures.pysrc/tunacode/ui/renderers/tools/base.pysrc/tunacode/ui/renderers/panels.pysrc/tunacode/ui/renderers/tools/hashline_edit.pysrc/tunacode/types/base.pysrc/tunacode/ui/renderers/tools/write_file.pysrc/tunacode/core/session/state.pysrc/tunacode/types/callbacks.pysrc/tunacode/types/__init__.py
src/tunacode/types/**/*.py
⚙️ CodeRabbit configuration file
src/tunacode/types/**/*.py: Type layer is at the bottom of the dependency hierarchy.
- types/ MUST NOT import from ui/, core/, or tools/
- Only standard library and typing imports allowed
- All type definitions must have proper annotations
- Canonical types (PR
#293) are immutable - use frozen=True
Files:
src/tunacode/types/tool_args.pysrc/tunacode/types/base.pysrc/tunacode/types/callbacks.pysrc/tunacode/types/__init__.py
🪛 Ruff (0.15.20)
src/tunacode/ui/renderers/tools/discover.py
[warning] 164-164: Unused method argument: args
(ARG002)
🔇 Additional comments (14)
src/tunacode/core/session/state.py (2)
23-23: LGTM!
45-63: 🩺 Stability & AvailabilityNo dangling
SessionStatefield accesses remain.> Likely an incorrect or invalid review comment.src/tunacode/core/types/state_structures.py (2)
57-58: 🩺 Stability & AvailabilityNo
runtime.streaming_panelaccess remains.
6-6: 🩺 Stability & AvailabilityNo issue here
Anyis not referenced insrc/tunacode/core/types/state_structures.py, andfrom __future__ import annotationsprevents import-time evaluation of annotations.> Likely an incorrect or invalid review comment.src/tunacode/types/tool_args.py (1)
1-33: LGTM!src/tunacode/types/__init__.py (1)
67-75: LGTM!src/tunacode/ui/renderers/tools/hashline_edit.py (1)
9-17: LGTM!Also applies to: 74-74, 90-91, 355-355, 412-412
src/tunacode/ui/renderers/tools/read_file.py (1)
11-11: LGTM!Also applies to: 20-20, 128-128, 162-164, 273-273
src/tunacode/ui/renderers/tools/web_fetch.py (1)
9-16: LGTM!Also applies to: 44-54, 188-188
src/tunacode/ui/renderers/tools/write_file.py (1)
10-10: LGTM!Also applies to: 21-21, 49-61, 165-165
src/tunacode/ui/renderers/panels.py (1)
20-20: LGTM!Also applies to: 88-88, 468-468, 524-524
src/tunacode/ui/renderers/tools/base.py (1)
17-17: LGTM!Also applies to: 32-32, 133-133, 204-204, 308-318, 426-426
src/tunacode/ui/renderers/tools/bash.py (1)
10-16: LGTM!Also applies to: 46-46, 91-92, 251-251
src/tunacode/types/base.py (1)
19-19: 🗄️ Data Integrity & IntegrationNo dangling imports remain for the removed type aliases.
> Likely an incorrect or invalid review comment.
| tool_call_id: str | ||
| tool_name: str | ||
| args: str | dict[str, Any] | None | ||
| args: str | ToolArgs | None |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check the import of ToolArgs in callbacks.py
sed -n '1,14p' src/tunacode/types/callbacks.py | rg -n 'ToolArgs'Repository: alchemiststudiosDOTai/tunacode
Length of output: 168
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the full imports and relevant type usage in the target file.
wc -l src/tunacode/types/callbacks.py
cat -n src/tunacode/types/callbacks.py | sed -n '1,120p'Repository: alchemiststudiosDOTai/tunacode
Length of output: 3102
src/tunacode/types/callbacks.py violates the types-layer import gate
ToolArgs, ToolName, and ToolResult are imported from tunacode.types.base, but src/tunacode/types/**/*.py is limited to stdlib/typing imports. Keep this module self-contained or move the shared aliases out of types/.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tunacode/types/callbacks.py` at line 38, Update the callback type
definitions around the args annotation to remove imports of ToolArgs, ToolName,
and ToolResult from tunacode.types.base, keeping src/tunacode/types
self-contained with only stdlib/typing dependencies. Define the necessary shared
aliases locally or move them to an allowed shared location, then update the
callback annotations to use those aliases without violating the types-layer
import gate.
Source: Path instructions
| return "" | ||
|
|
||
| def parse_result(self, args: dict[str, Any] | None, result: str) -> DiscoverData | None: | ||
| def parse_result(self, args: ToolArgs | None, result: str) -> DiscoverData | None: |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Unused args parameter (Ruff ARG002).
DiscoverRenderer.parse_result never reads args, unlike the other renderers in this cohort that cast it to a tool-specific schema. Silence the lint warning or confirm this is intentionally unused (discover has no DiscoverArgs schema).
🧹 Proposed fix
- def parse_result(self, args: ToolArgs | None, result: str) -> DiscoverData | None:
+ def parse_result(self, args: ToolArgs | None, result: str) -> DiscoverData | None: # noqa: ARG002📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def parse_result(self, args: ToolArgs | None, result: str) -> DiscoverData | None: | |
| def parse_result(self, args: ToolArgs | None, result: str) -> DiscoverData | None: # noqa: ARG002 |
🧰 Tools
🪛 Ruff (0.15.20)
[warning] 164-164: Unused method argument: args
(ARG002)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tunacode/ui/renderers/tools/discover.py` at line 164, Update
DiscoverRenderer.parse_result to explicitly mark the intentionally unused args
parameter, such as by assigning it to the project’s standard unused-variable
convention, while preserving the existing result parsing behavior; do not
introduce a DiscoverArgs schema.
Source: Linters/SAST tools
| from tunacode.types import ToolArgs | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Consider typing as BashArgs instead of the broader ToolArgs.
This literal is only ever consumed by render_bash/BashRenderer, which casts to BashArgs. Annotating it as BashArgs directly would let mypy catch a wrong/misspelled key here instead of silently allowing any JSON-object shape.
♻️ Proposed tightening
- from tunacode.types import ToolArgs
+ from tunacode.types import BashArgs
from tunacode.ui.renderers.tools.bash import render_bash
...
- args: ToolArgs = {"timeout": int(SHELL_COMMAND_TIMEOUT_SECONDS)}
+ args: BashArgs = {"timeout": int(SHELL_COMMAND_TIMEOUT_SECONDS)}Also applies to: 161-161
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tunacode/ui/shell_runner.py` around lines 144 - 145, Update the type
annotation for the bash tool argument literals in the shell runner to use
BashArgs instead of the broader ToolArgs. Apply this at both annotated
occurrences, including the literal consumed by render_bash/BashRenderer, and
adjust the import accordingly so mypy validates the expected BashArgs keys.
Field-level trace of the five data boundaries (tool args, session
persistence, agent messages, runtime state, UI display shapes), the
concrete shapes flowing through each Any annotation, dead-code
inventory, and the target type design. Includes an HTML visualization
of the same map.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01U3DHf5FbGZiDLMSWpq53gK
Summary
TypedDictschemas and narrowed tool-call, renderer, and UI panel arguments from generic dictionaries toToolArgsand tool-specific types.Validation
mypypasses cleanly.