tunacode-cli 0.1.37__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tunacode_cli-0.1.37/.claude/JOURNAL.md +359 -0
- tunacode_cli-0.1.37/.claude/debug_history/2026-01-12_missing-cached-tokens.md +45 -0
- tunacode_cli-0.1.37/.claude/debug_history/list-dir-tool-execution-error.md +55 -0
- tunacode_cli-0.1.37/.claude/delta/2026-01-17-dangling-tool-calls.md +171 -0
- tunacode_cli-0.1.37/.claude/delta/remove-global-cache-user-config.md +54 -0
- tunacode_cli-0.1.37/.claude/qa/no-cargo-cult-fixes.md +52 -0
- tunacode_cli-0.1.37/.claude/qa/raw.md +2 -0
- tunacode_cli-0.1.37/.claude/qa/semantically-dead-code.md +85 -0
- tunacode_cli-0.1.37/.github/pull_request_template.md +51 -0
- tunacode_cli-0.1.37/.github/workflows/lint.yml +20 -0
- tunacode_cli-0.1.37/.github/workflows/publish-release.yml +73 -0
- tunacode_cli-0.1.37/.gitignore +86 -0
- tunacode_cli-0.1.37/.pre-commit-config.yaml +148 -0
- tunacode_cli-0.1.37/AGENTS.md +304 -0
- tunacode_cli-0.1.37/CHANGELOG.md +205 -0
- tunacode_cli-0.1.37/CLAUDE.md +441 -0
- tunacode_cli-0.1.37/CONTRIBUTING.md +148 -0
- tunacode_cli-0.1.37/LICENSE +21 -0
- tunacode_cli-0.1.37/MANIFEST.in +20 -0
- tunacode_cli-0.1.37/PKG-INFO +176 -0
- tunacode_cli-0.1.37/README.md +124 -0
- tunacode_cli-0.1.37/assets/tunacode.png +0 -0
- tunacode_cli-0.1.37/assets/tunacode_example.png +0 -0
- tunacode_cli-0.1.37/docs/codebase-map/MAP.md +465 -0
- tunacode_cli-0.1.37/docs/codebase-map/architecture/architecture.md +809 -0
- tunacode_cli-0.1.37/docs/codebase-map/architecture/conversation-turns.md +403 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/00-overview.md +57 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/INDEX.md +123 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/configuration.md +98 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/constants.md +170 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-agents.md +225 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-compaction.md +163 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-limits.md +171 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-logging.md +100 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-prompting.md +119 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/core-state.md +57 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/exceptions.md +187 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/indexing.md +96 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/lsp.md +112 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/prompts.md +151 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/templates.md +113 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/tools-overview.md +232 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/types.md +95 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/ui-overview.md +202 -0
- tunacode_cli-0.1.37/docs/codebase-map/modules/utils.md +134 -0
- tunacode_cli-0.1.37/docs/codebase-map/state/state.md +324 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/00-root-overview.md +82 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/01-ui-directory.md +131 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/02-core-directory.md +135 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/03-tools-directory.md +171 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/04-configuration-directory.md +171 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/05-cli-directory.md +122 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/06-supporting-modules.md +214 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/ANALYSIS_SUMMARY.md +266 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/README.md +231 -0
- tunacode_cli-0.1.37/docs/codebase-map/structure/tree-structure.txt +261 -0
- tunacode_cli-0.1.37/docs/configuration/README.md +90 -0
- tunacode_cli-0.1.37/docs/configuration/tunacode.json.example +36 -0
- tunacode_cli-0.1.37/docs/configuration/tunacode.local.json.example +34 -0
- tunacode_cli-0.1.37/docs/images/logo.jpeg +0 -0
- tunacode_cli-0.1.37/docs/images/logo_clear.png +0 -0
- tunacode_cli-0.1.37/docs/images/theme.png +0 -0
- tunacode_cli-0.1.37/docs/images/tui-model-setup.png +0 -0
- tunacode_cli-0.1.37/docs/images/tui.png +0 -0
- tunacode_cli-0.1.37/docs/media/agent-response.png +0 -0
- tunacode_cli-0.1.37/docs/media/plan-approval.png +0 -0
- tunacode_cli-0.1.37/docs/media/read-file-tool.png +0 -0
- tunacode_cli-0.1.37/docs/media/tc-logo.jpg +0 -0
- tunacode_cli-0.1.37/docs/tools/architecture.md +221 -0
- tunacode_cli-0.1.37/docs/ui/agent_response_panel.md +91 -0
- tunacode_cli-0.1.37/docs/ui/design_philosophy.md +26 -0
- tunacode_cli-0.1.37/docs/ui/layout.md +61 -0
- tunacode_cli-0.1.37/docs/ui/nextstep_panels.md +108 -0
- tunacode_cli-0.1.37/docs/ui/shell_runner.md +113 -0
- tunacode_cli-0.1.37/docs/ui/tool_renderers.md +266 -0
- tunacode_cli-0.1.37/memory-bank/execute/2026-01-07_23-25-00_glob-grep-modelretry.md +121 -0
- tunacode_cli-0.1.37/memory-bank/execute/2026-01-08_22-30-00_agent-response-panel.md +55 -0
- tunacode_cli-0.1.37/memory-bank/execute/2026-01-09_19-05-00_register-present-plan-tool-222.md +95 -0
- tunacode_cli-0.1.37/memory-bank/execute/2026-01-10_14-45-00_dead-code-m1.md +78 -0
- tunacode_cli-0.1.37/memory-bank/execute/2026-01-19_15-30-00_timeout_cleanup_gap.md +153 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-07_16-30-00_renderer-unification.md +156 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-07_23-12-56_glob-grep-modelretry.md +165 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-08_agent-response-panel.md +211 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-09_19-00-00_register-present-plan-tool-222.md +139 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-10_09-40-00_shell_panel_nextstep_standardization.md +280 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-10_14-10-34_dead-code-dry-cleanup.md +160 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-11_app-py-decomposition.md +200 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-12_15-45-00_node_processor_cleanup.md +215 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-14_13-15-00_centralized-ignore-patterns.md +152 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-15_slim-panels-ui-update.md +252 -0
- tunacode_cli-0.1.37/memory-bank/plan/2026-01-19_15-00-00_timeout_cleanup_gap.md +147 -0
- tunacode_cli-0.1.37/memory-bank/plan/assets/dream-mockup-slim-panels.webp +0 -0
- tunacode_cli-0.1.37/memory-bank/plan/subplan-renderer-ui.md +139 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-07_23-10-22_glob-grep-error-strings.md +207 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-07_panel-architecture-map.md +229 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-07_pydantic-v2-analysis.md +142 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_14-14-39_local-mode-docs.md +147 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_14-20-00_messages-and-pruning-local-vs-api.md +229 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_23-46-19_plan-permission-keeps-asking.md +150 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_agent-reply-rendering-analysis.md +178 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_raw-code-rendering-gaps.md +255 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-08_ui-model-selector-logic.md +257 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-09_11-33-26_grep-read-performance.md +203 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-09_18-41-11_register-present-plan-tool-222.md +131 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-09_simple-prompt-evals.md +153 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-10_09-33-00_shell_panel_nextstep_standardization.md +264 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-10_agent_config_map.md +279 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-11_16-57-40_plan-tool-and-workflow.md +265 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-12-000000_parallel_tool_call_execution.md +188 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-12-22-30-59_agent_components_codebase_mapping.md +459 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-12_12-42-33_parallel-tool-calling-not-working.md +109 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-12_15-30-07_node_processor_mapping.md +220 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-14_12-27-29_glob-tool-bottlenecks.md +298 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-14_12-50-37_centralized-ignore-patterns.md +193 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-14_streaming-architecture.md +254 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-15_option-c-grouped-sections.md +257 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-15_tool-panel-redesign-options.md +290 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-15_tool-panel-scrolling-readability.md +175 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-16_10-59-35_tool-panel-architecture.md +161 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-16_11-04-37_streaming-architecture.md +272 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-16_13-57-44_hook-arrow-file-indicator.md +130 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-16_tool-panel-resize-truncation.md +140 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-19_12-03-10_pydantic_ai_tool_call_wire_format.md +230 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-19_12-43-23_utils_code_smells_analysis.md +232 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-19_14-30-00_dangling_tool_calls_timeout_gap.md +207 -0
- tunacode_cli-0.1.37/memory-bank/research/2026-01-19_14-38-26_ui_code_smells_analysis.md +441 -0
- tunacode_cli-0.1.37/memory-bank/research/bash.md +260 -0
- tunacode_cli-0.1.37/pyproject.toml +192 -0
- tunacode_cli-0.1.37/pytest.ini +36 -0
- tunacode_cli-0.1.37/scripts/check-file-length.sh +101 -0
- tunacode_cli-0.1.37/scripts/check-unused-constants.py +142 -0
- tunacode_cli-0.1.37/scripts/download_ripgrep.py +176 -0
- tunacode_cli-0.1.37/scripts/install_linux.sh +551 -0
- tunacode_cli-0.1.37/scripts/playwright_cache.py +141 -0
- tunacode_cli-0.1.37/scripts/preview_tool_panels.py +489 -0
- tunacode_cli-0.1.37/scripts/run-dead-imports.sh +82 -0
- tunacode_cli-0.1.37/scripts/startup_timer.py +272 -0
- tunacode_cli-0.1.37/scripts/ui_import_timer.py +194 -0
- tunacode_cli-0.1.37/scripts/uninstall.sh +481 -0
- tunacode_cli-0.1.37/scripts/update_models_registry.sh +4 -0
- tunacode_cli-0.1.37/scripts/utils/vulture_whitelist.py +10 -0
- tunacode_cli-0.1.37/src/tunacode/__init__.py +0 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/__init__.py +1 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/defaults.py +45 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/models.py +163 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/models_registry.json +1 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/pricing.py +74 -0
- tunacode_cli-0.1.37/src/tunacode/configuration/settings.py +36 -0
- tunacode_cli-0.1.37/src/tunacode/constants.py +224 -0
- tunacode_cli-0.1.37/src/tunacode/core/__init__.py +6 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/__init__.py +35 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/__init__.py +37 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/agent_config.py +453 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/agent_helpers.py +221 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/message_handler.py +31 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/__init__.py +5 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/message_recorder.py +8 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/orchestrator.py +167 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/tool_dispatcher.py +348 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/orchestrator/usage_tracker.py +48 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/response_state.py +129 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/result_wrapper.py +51 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/state_transition.py +117 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/streaming.py +291 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/tool_buffer.py +44 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/tool_executor.py +116 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/agent_components/truncation_checker.py +37 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/delegation_tools.py +109 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/main.py +566 -0
- tunacode_cli-0.1.37/src/tunacode/core/agents/research_agent.py +242 -0
- tunacode_cli-0.1.37/src/tunacode/core/compaction.py +237 -0
- tunacode_cli-0.1.37/src/tunacode/core/limits.py +96 -0
- tunacode_cli-0.1.37/src/tunacode/core/logging/__init__.py +24 -0
- tunacode_cli-0.1.37/src/tunacode/core/logging/handlers.py +170 -0
- tunacode_cli-0.1.37/src/tunacode/core/logging/levels.py +17 -0
- tunacode_cli-0.1.37/src/tunacode/core/logging/manager.py +160 -0
- tunacode_cli-0.1.37/src/tunacode/core/logging/records.py +22 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/__init__.py +29 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/loader.py +66 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/local_prompt.md +72 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/prompting_engine.py +98 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/sections.py +50 -0
- tunacode_cli-0.1.37/src/tunacode/core/prompting/templates.py +85 -0
- tunacode_cli-0.1.37/src/tunacode/core/state.py +434 -0
- tunacode_cli-0.1.37/src/tunacode/exceptions.py +313 -0
- tunacode_cli-0.1.37/src/tunacode/indexing/__init__.py +5 -0
- tunacode_cli-0.1.37/src/tunacode/indexing/code_index.py +432 -0
- tunacode_cli-0.1.37/src/tunacode/indexing/constants.py +53 -0
- tunacode_cli-0.1.37/src/tunacode/lsp/__init__.py +110 -0
- tunacode_cli-0.1.37/src/tunacode/lsp/client.py +352 -0
- tunacode_cli-0.1.37/src/tunacode/lsp/diagnostics.py +19 -0
- tunacode_cli-0.1.37/src/tunacode/lsp/servers.py +101 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/default_prompt.md +955 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/agent_role.xml +5 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/constraints.xml +14 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/output_format.xml +57 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/research/sections/tool_use.xml +23 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/advanced_patterns.xml +255 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/agent_role.xml +8 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/completion.xml +9 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/critical_rules.xml +37 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/examples.xml +220 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/output_style.xml +94 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/parallel_exec.xml +109 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/search_pattern.xml +100 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/system_info.xml +6 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/tool_use.xml +90 -0
- tunacode_cli-0.1.37/src/tunacode/prompts/sections/user_instructions.xml +3 -0
- tunacode_cli-0.1.37/src/tunacode/py.typed +0 -0
- tunacode_cli-0.1.37/src/tunacode/templates/__init__.py +5 -0
- tunacode_cli-0.1.37/src/tunacode/templates/loader.py +15 -0
- tunacode_cli-0.1.37/src/tunacode/tools/__init__.py +10 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/__init__.py +29 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/context.py +33 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/factory.py +22 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/handler.py +65 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/notifier.py +40 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/policy.py +40 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/requests.py +120 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/rules.py +91 -0
- tunacode_cli-0.1.37/src/tunacode/tools/authorization/types.py +18 -0
- tunacode_cli-0.1.37/src/tunacode/tools/bash.py +223 -0
- tunacode_cli-0.1.37/src/tunacode/tools/decorators.py +218 -0
- tunacode_cli-0.1.37/src/tunacode/tools/glob.py +357 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep.py +469 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep_components/__init__.py +9 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep_components/file_filter.py +91 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep_components/pattern_matcher.py +158 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep_components/result_formatter.py +87 -0
- tunacode_cli-0.1.37/src/tunacode/tools/grep_components/search_result.py +34 -0
- tunacode_cli-0.1.37/src/tunacode/tools/ignore.py +177 -0
- tunacode_cli-0.1.37/src/tunacode/tools/list_dir.py +173 -0
- tunacode_cli-0.1.37/src/tunacode/tools/present_plan.py +102 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/bash_prompt.xml +10 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/glob_prompt.xml +7 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/grep_prompt.xml +10 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/list_dir_prompt.xml +7 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/present_plan_prompt.xml +42 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/read_file_prompt.xml +9 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/submit_prompt.xml +8 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/todoclear_prompt.xml +12 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/todoread_prompt.xml +16 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/todowrite_prompt.xml +28 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/update_file_prompt.xml +9 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
- tunacode_cli-0.1.37/src/tunacode/tools/prompts/write_file_prompt.xml +7 -0
- tunacode_cli-0.1.37/src/tunacode/tools/react.py +111 -0
- tunacode_cli-0.1.37/src/tunacode/tools/read_file.py +96 -0
- tunacode_cli-0.1.37/src/tunacode/tools/submit.py +45 -0
- tunacode_cli-0.1.37/src/tunacode/tools/todo.py +222 -0
- tunacode_cli-0.1.37/src/tunacode/tools/update_file.py +62 -0
- tunacode_cli-0.1.37/src/tunacode/tools/utils/__init__.py +1 -0
- tunacode_cli-0.1.37/src/tunacode/tools/utils/ripgrep.py +340 -0
- tunacode_cli-0.1.37/src/tunacode/tools/utils/text_match.py +352 -0
- tunacode_cli-0.1.37/src/tunacode/tools/web_fetch.py +245 -0
- tunacode_cli-0.1.37/src/tunacode/tools/write_file.py +34 -0
- tunacode_cli-0.1.37/src/tunacode/tools/xml_helper.py +34 -0
- tunacode_cli-0.1.37/src/tunacode/types/__init__.py +170 -0
- tunacode_cli-0.1.37/src/tunacode/types/base.py +94 -0
- tunacode_cli-0.1.37/src/tunacode/types/callbacks.py +55 -0
- tunacode_cli-0.1.37/src/tunacode/types/dataclasses.py +121 -0
- tunacode_cli-0.1.37/src/tunacode/types/pydantic_ai.py +66 -0
- tunacode_cli-0.1.37/src/tunacode/types/state.py +138 -0
- tunacode_cli-0.1.37/src/tunacode/ui/__init__.py +6 -0
- tunacode_cli-0.1.37/src/tunacode/ui/app.py +557 -0
- tunacode_cli-0.1.37/src/tunacode/ui/assets/logo.ansi +9 -0
- tunacode_cli-0.1.37/src/tunacode/ui/commands/__init__.py +534 -0
- tunacode_cli-0.1.37/src/tunacode/ui/headless/__init__.py +5 -0
- tunacode_cli-0.1.37/src/tunacode/ui/headless/output.py +72 -0
- tunacode_cli-0.1.37/src/tunacode/ui/logo_assets.py +20 -0
- tunacode_cli-0.1.37/src/tunacode/ui/main.py +252 -0
- tunacode_cli-0.1.37/src/tunacode/ui/plan_approval.py +144 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/__init__.py +41 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/agent_response.py +221 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/errors.py +197 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/panel_widths.py +14 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/panels.py +554 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/search.py +313 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/__init__.py +73 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/base.py +480 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/bash.py +254 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/diagnostics.py +186 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/glob.py +230 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/grep.py +232 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/list_dir.py +226 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/read_file.py +230 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/research.py +294 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/syntax_utils.py +227 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/update_file.py +272 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/web_fetch.py +191 -0
- tunacode_cli-0.1.37/src/tunacode/ui/renderers/tools/write_file.py +168 -0
- tunacode_cli-0.1.37/src/tunacode/ui/repl_support.py +234 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/__init__.py +16 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/model_picker.py +303 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/session_picker.py +181 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/setup.py +218 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/theme_picker.py +90 -0
- tunacode_cli-0.1.37/src/tunacode/ui/screens/update_confirm.py +69 -0
- tunacode_cli-0.1.37/src/tunacode/ui/shell_runner.py +267 -0
- tunacode_cli-0.1.37/src/tunacode/ui/startup.py +57 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles/layout.tcss +99 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles/modals.tcss +38 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles/panels.tcss +81 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles/theme-nextstep.tcss +320 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles/widgets.tcss +39 -0
- tunacode_cli-0.1.37/src/tunacode/ui/styles.py +18 -0
- tunacode_cli-0.1.37/src/tunacode/ui/welcome.py +69 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/__init__.py +23 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/command_autocomplete.py +62 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/editor.py +402 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/file_autocomplete.py +47 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/messages.py +46 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/resource_bar.py +179 -0
- tunacode_cli-0.1.37/src/tunacode/ui/widgets/status_bar.py +98 -0
- tunacode_cli-0.1.37/src/tunacode/utils/__init__.py +0 -0
- tunacode_cli-0.1.37/src/tunacode/utils/config/__init__.py +13 -0
- tunacode_cli-0.1.37/src/tunacode/utils/config/user_configuration.py +62 -0
- tunacode_cli-0.1.37/src/tunacode/utils/messaging/__init__.py +9 -0
- tunacode_cli-0.1.37/src/tunacode/utils/messaging/message_utils.py +34 -0
- tunacode_cli-0.1.37/src/tunacode/utils/messaging/token_counter.py +20 -0
- tunacode_cli-0.1.37/src/tunacode/utils/parsing/__init__.py +13 -0
- tunacode_cli-0.1.37/src/tunacode/utils/parsing/command_parser.py +56 -0
- tunacode_cli-0.1.37/src/tunacode/utils/parsing/json_utils.py +158 -0
- tunacode_cli-0.1.37/src/tunacode/utils/parsing/retry.py +153 -0
- tunacode_cli-0.1.37/src/tunacode/utils/parsing/tool_parser.py +350 -0
- tunacode_cli-0.1.37/src/tunacode/utils/system/__init__.py +25 -0
- tunacode_cli-0.1.37/src/tunacode/utils/system/gitignore.py +80 -0
- tunacode_cli-0.1.37/src/tunacode/utils/system/ignore_patterns.py +130 -0
- tunacode_cli-0.1.37/src/tunacode/utils/system/paths.py +190 -0
- tunacode_cli-0.1.37/src/tunacode/utils/ui/__init__.py +9 -0
- tunacode_cli-0.1.37/src/tunacode/utils/ui/file_filter.py +116 -0
- tunacode_cli-0.1.37/src/tunacode/utils/ui/helpers.py +24 -0
- tunacode_cli-0.1.37/tests/__init__.py +1 -0
- tunacode_cli-0.1.37/tests/conftest.py +19 -0
- tunacode_cli-0.1.37/tests/test_base_renderer.py +88 -0
- tunacode_cli-0.1.37/tests/test_base_tool_renderer.py +193 -0
- tunacode_cli-0.1.37/tests/test_cli_default_command.py +29 -0
- tunacode_cli-0.1.37/tests/test_compaction.py +349 -0
- tunacode_cli-0.1.37/tests/test_confirmation_preview.py +46 -0
- tunacode_cli-0.1.37/tests/test_diagnostics_renderer.py +175 -0
- tunacode_cli-0.1.37/tests/test_exceptions.py +94 -0
- tunacode_cli-0.1.37/tests/test_glob_grep_path_validation.py +70 -0
- tunacode_cli-0.1.37/tests/test_headless_cli.py +37 -0
- tunacode_cli-0.1.37/tests/test_limits.py +245 -0
- tunacode_cli-0.1.37/tests/test_logging.py +295 -0
- tunacode_cli-0.1.37/tests/test_message_utils.py +92 -0
- tunacode_cli-0.1.37/tests/test_present_plan.py +118 -0
- tunacode_cli-0.1.37/tests/test_prompting_engine.py +90 -0
- tunacode_cli-0.1.37/tests/test_repl_support.py +26 -0
- tunacode_cli-0.1.37/tests/test_shell_command_escape.py +97 -0
- tunacode_cli-0.1.37/tests/test_shell_runner.py +103 -0
- tunacode_cli-0.1.37/tests/test_text_match.py +132 -0
- tunacode_cli-0.1.37/tests/test_todo_tools.py +48 -0
- tunacode_cli-0.1.37/tests/test_token_counter.py +79 -0
- tunacode_cli-0.1.37/tests/test_tool_call_lifecycle.py +895 -0
- tunacode_cli-0.1.37/tests/test_tool_conformance.py +143 -0
- tunacode_cli-0.1.37/tests/test_tool_decorators.py +219 -0
- tunacode_cli-0.1.37/tests/test_tool_dispatcher_coverage.py +376 -0
- tunacode_cli-0.1.37/tests/test_tool_parser.py +437 -0
- tunacode_cli-0.1.37/tests/test_tool_performance.py +281 -0
- tunacode_cli-0.1.37/tests/test_tool_retry.py +284 -0
- tunacode_cli-0.1.37/tests/test_update_file_renderer.py +20 -0
- tunacode_cli-0.1.37/tests/test_usage_tracker.py +35 -0
- tunacode_cli-0.1.37/tests/test_web_fetch.py +141 -0
- tunacode_cli-0.1.37/tests/tools/test_ignore.py +80 -0
- tunacode_cli-0.1.37/tests/unit/tools/test_submit.py +65 -0
- tunacode_cli-0.1.37/tests/unit/ui/test_agent_response.py +144 -0
- tunacode_cli-0.1.37/uv.lock +3560 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Claude Journal
|
|
2
|
+
|
|
3
|
+
## 2026-01-07: Renderer Unification
|
|
4
|
+
|
|
5
|
+
Unifying the 8 tool renderers in `src/tunacode/ui/renderers/tools/` to eliminate duplication via a shared base class and registry pattern.
|
|
6
|
+
|
|
7
|
+
### Completed:
|
|
8
|
+
- Created `base.py` with `BaseToolRenderer[T]` ABC and `ToolRendererProtocol`
|
|
9
|
+
- Extracted shared helpers: `truncate_line`, `truncate_content`, `pad_lines`
|
|
10
|
+
- Added registry pattern: `@tool_renderer`, `get_renderer`, `list_renderers`
|
|
11
|
+
- Migrated `list_dir.py` to use `BaseToolRenderer` (199 -> 149 lines)
|
|
12
|
+
- Created documentation at `docs/ui/tool_renderers.md`
|
|
13
|
+
|
|
14
|
+
### Architecture Decisions:
|
|
15
|
+
- Module-level singleton renderer instances (not created per-call)
|
|
16
|
+
- Render functions remain the public API (backward compatible)
|
|
17
|
+
- `@tool_renderer` decorator for self-registration
|
|
18
|
+
- Helpers are standalone functions, not methods
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2026-01-07: Local Mode Context Optimization
|
|
23
|
+
|
|
24
|
+
### Problem:
|
|
25
|
+
- System prompt + tool schemas used ~3.5k tokens before any conversation
|
|
26
|
+
- Each file read could use 2000 lines (~20k tokens)
|
|
27
|
+
- With 10k context, only ~6.5k left for conversation
|
|
28
|
+
- LLM APIs are stateless - system prompt sent every turn
|
|
29
|
+
|
|
30
|
+
### Solution:
|
|
31
|
+
|
|
32
|
+
**1. Minimal System Prompt**
|
|
33
|
+
- `LOCAL_TEMPLATE` in `templates.py` - only 3 sections: AGENT_ROLE, TOOL_USE, USER_INSTRUCTIONS
|
|
34
|
+
- `local_mode: true` setting triggers minimal template
|
|
35
|
+
|
|
36
|
+
**2. Minimal Tool Schemas**
|
|
37
|
+
- Reduced from 11 tools to 6 (bash, read_file, update_file, write_file, glob, list_dir)
|
|
38
|
+
- 1-word descriptions ("Shell", "Read", "Edit", etc.) - saves ~1k tokens
|
|
39
|
+
|
|
40
|
+
**3. Aggressive Pruning**
|
|
41
|
+
- LOCAL_PRUNE_PROTECT_TOKENS: 2,000 (vs 40,000)
|
|
42
|
+
- LOCAL_PRUNE_MINIMUM_THRESHOLD: 500 (vs 20,000)
|
|
43
|
+
|
|
44
|
+
**4. Tool Output Limits**
|
|
45
|
+
- LOCAL_DEFAULT_READ_LIMIT: 200 lines (vs 2,000)
|
|
46
|
+
- LOCAL_MAX_LINE_LENGTH: 500 chars (vs 2,000)
|
|
47
|
+
- LOCAL_MAX_COMMAND_OUTPUT: 1,500 chars (vs 5,000)
|
|
48
|
+
|
|
49
|
+
**5. Response Limit**
|
|
50
|
+
- local_max_tokens: 1000 - caps model output per turn
|
|
51
|
+
|
|
52
|
+
### Token Budget (Local Mode):
|
|
53
|
+
| Component | Tokens |
|
|
54
|
+
|-----------|--------|
|
|
55
|
+
| System prompt | ~1,100 |
|
|
56
|
+
| Guide file | ~500 |
|
|
57
|
+
| 6 tools (minimal) | ~575 |
|
|
58
|
+
| **Total base** | **~2,200** |
|
|
59
|
+
|
|
60
|
+
With 10k context: ~7.8k available for conversation.
|
|
61
|
+
|
|
62
|
+
### Key Insight:
|
|
63
|
+
LLM APIs are stateless. Every request sends: system prompt + tool schemas + full conversation history. Model has no memory - re-reads everything each turn.
|
|
64
|
+
|
|
65
|
+
### Key Files:
|
|
66
|
+
- `src/tunacode/core/limits.py` - Centralized limit configuration
|
|
67
|
+
- `src/tunacode/core/prompting/templates.py` - LOCAL_TEMPLATE
|
|
68
|
+
- `src/tunacode/core/prompting/local_prompt.md` - Condensed prompt
|
|
69
|
+
- `src/tunacode/core/compaction.py` - Dynamic prune thresholds
|
|
70
|
+
- `src/tunacode/constants.py` - Local mode limit constants
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2026-01-06: Local Model Support
|
|
75
|
+
|
|
76
|
+
### Task: Add local model support to tunacode
|
|
77
|
+
|
|
78
|
+
### Completed:
|
|
79
|
+
- Created condensed system prompt at `src/tunacode/prompts/local_model_prompt.txt` (~500 bytes vs 34KB full prompt)
|
|
80
|
+
- Added `local_model: true/false` setting in config defaults
|
|
81
|
+
- Modified `load_system_prompt()` to use condensed prompt when `local_model=true`
|
|
82
|
+
- Added cache invalidation for `local_model` setting in `_compute_agent_version()`
|
|
83
|
+
- Skip AGENTS.md loading for local models to save tokens
|
|
84
|
+
- Created `fallback_executor.py` for models that output tool calls in text (e.g., `<tool_call>` tags)
|
|
85
|
+
- Updated `node_processor.py` to detect and execute fallback tool calls
|
|
86
|
+
- Passed `agent_ctx` through the call chain for result injection
|
|
87
|
+
- Tested with multiple local models via LM Studio/vLLM
|
|
88
|
+
|
|
89
|
+
### Notes:
|
|
90
|
+
- Qwen2.5-Coder-14B supports native OpenAI tool calling format
|
|
91
|
+
- Smaller models (0.6B-1.7B) output `<tool_call>` tags in content - fallback parser handles this
|
|
92
|
+
- llama.cpp uses KV cache efficiently (LCP similarity) so repeated prompt not re-computed
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 2026-01-08: Config Restoration & Local Mode Docs
|
|
97
|
+
|
|
98
|
+
### Task: Restore pre-local-mode config and document local mode setup
|
|
99
|
+
|
|
100
|
+
### Completed:
|
|
101
|
+
|
|
102
|
+
**1. Config Backup Discovery**
|
|
103
|
+
Found three config variants in `~/.config/`:
|
|
104
|
+
- `tunacode.json` - was set to local mode (grok-code-fast-1, 10k context)
|
|
105
|
+
- `tunacode.json.bak` - MiniMax-M2.1, 200k context, no local mode
|
|
106
|
+
- `@tunacode.json` - Gemini 3 Pro via OpenRouter
|
|
107
|
+
|
|
108
|
+
**2. Restored Config**
|
|
109
|
+
- Restored `~/.config/tunacode.json` from `.bak` (MiniMax config)
|
|
110
|
+
- Settings: `minimax:MiniMax-M2.1`, 200k context, `guide_file: AGENTS.md`
|
|
111
|
+
|
|
112
|
+
**3. Created Local Mode Example**
|
|
113
|
+
- Created `docs/configuration/tunacode.local.json.example`
|
|
114
|
+
- Documents all local mode settings:
|
|
115
|
+
- `local_mode: true`
|
|
116
|
+
- `local_max_tokens: 1000`
|
|
117
|
+
- `context_window_size: 10000`
|
|
118
|
+
- `OPENAI_BASE_URL: http://127.0.0.1:8080/v1`
|
|
119
|
+
- `guide_file: CLAUDE_LOCAL.md`
|
|
120
|
+
|
|
121
|
+
### Key Files:
|
|
122
|
+
- `~/.config/tunacode.json` - user config (restored to MiniMax)
|
|
123
|
+
- `docs/configuration/tunacode.json.example` - standard example
|
|
124
|
+
- `docs/configuration/tunacode.local.json.example` - NEW: local mode example
|
|
125
|
+
|
|
126
|
+
### Notes:
|
|
127
|
+
- Local mode uses condensed prompts and minimal tool schemas for small context windows
|
|
128
|
+
- The `.bak` file preserved the pre-experimentation state - good backup hygiene!
|
|
129
|
+
- User was testing local models, now back to cloud (MiniMax)
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 2026-01-08: Syntax Highlighting for Tool Renderers (Branch: ui-model-work)
|
|
134
|
+
|
|
135
|
+
### The Mission:
|
|
136
|
+
Make tool outputs pretty! All those ugly plain text viewports were a crime against NeXTSTEP aesthetics. Time to add syntax highlighting everywhere.
|
|
137
|
+
|
|
138
|
+
### Completed (Commit 9db8e92):
|
|
139
|
+
|
|
140
|
+
**1. Created `syntax_utils.py` - The Shared Foundation**
|
|
141
|
+
- `EXTENSION_LEXERS` - 60+ file extension → lexer mappings
|
|
142
|
+
- `get_lexer(filepath)` - Get pygments lexer from file path
|
|
143
|
+
- `syntax_or_text(content, filepath)` - Render highlighted or plain
|
|
144
|
+
- `detect_code_lexer(content)` - Heuristic code detection (shebangs, JSON, Python/JS patterns)
|
|
145
|
+
- `SYNTAX_THEME = "monokai"` - Consistent theme everywhere
|
|
146
|
+
|
|
147
|
+
**2. Created `write_file.py` - New Renderer!**
|
|
148
|
+
- Was missing entirely - now shows syntax-highlighted preview of written content
|
|
149
|
+
- Green "NEW" badge in header, file stats
|
|
150
|
+
|
|
151
|
+
**3. Updated 8 Existing Renderers:**
|
|
152
|
+
|
|
153
|
+
| Renderer | What Changed |
|
|
154
|
+
|----------|-------------|
|
|
155
|
+
| `read_file` | Syntax highlighting by file extension, built-in line numbers from Syntax component |
|
|
156
|
+
| `grep` | Cyan file paths, yellow `reverse` highlighted matches, styled line numbers with `│` |
|
|
157
|
+
| `glob` | Files colored by type: Python=bright_blue, JS=yellow, JSON=green, etc. Dir path dim, filename bold |
|
|
158
|
+
| `list_dir` | Tree chars dim, directories bold cyan, files colored by lexer type |
|
|
159
|
+
| `bash` | Smart detection: `git diff`→diff lexer, JSON commands→json lexer, labeled stdout/stderr |
|
|
160
|
+
| `web_fetch` | URL-based detection (raw.githubusercontent.com, .json, /api/), content heuristics |
|
|
161
|
+
| `research` | New "Code" section with syntax-highlighted examples from `code_examples` field |
|
|
162
|
+
| `update_file` | Already had Syntax("diff") - unchanged, the OG |
|
|
163
|
+
|
|
164
|
+
**4. Updated `__init__.py`:**
|
|
165
|
+
- Added `write_file` renderer to exports
|
|
166
|
+
- Added syntax utility functions to `__all__`
|
|
167
|
+
- Better docstring explaining the 4-zone pattern
|
|
168
|
+
|
|
169
|
+
### Key Design Decisions:
|
|
170
|
+
- `syntax_or_text()` returns `RenderableType` - graceful fallback to `Text()` for unknown extensions
|
|
171
|
+
- File-type coloring consistent across `glob`, `list_dir`, `grep` (same color = same type)
|
|
172
|
+
- Bash output detection is conservative - only highlights when confident
|
|
173
|
+
- Research viewport prioritizes findings over code (code is supplementary)
|
|
174
|
+
|
|
175
|
+
### Files Modified:
|
|
176
|
+
```
|
|
177
|
+
src/tunacode/ui/renderers/tools/
|
|
178
|
+
├── __init__.py (exports + docstring)
|
|
179
|
+
├── syntax_utils.py (NEW - shared utilities)
|
|
180
|
+
├── write_file.py (NEW - renderer)
|
|
181
|
+
├── read_file.py (syntax highlighting)
|
|
182
|
+
├── grep.py (styled matches)
|
|
183
|
+
├── glob.py (colored paths)
|
|
184
|
+
├── list_dir.py (styled tree)
|
|
185
|
+
├── bash.py (smart detection)
|
|
186
|
+
├── web_fetch.py (URL/content detection)
|
|
187
|
+
└── research.py (code examples)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### What's Left on This Branch:
|
|
191
|
+
- Other UI model work (the branch name suggests more to do)
|
|
192
|
+
- Unstaged: `.claude/JOURNAL.md`, `CLAUDE.md`, research docs, config example
|
|
193
|
+
|
|
194
|
+
### Commands:
|
|
195
|
+
```bash
|
|
196
|
+
uv run ruff check src/tunacode/ui/renderers/tools/ # All checks pass
|
|
197
|
+
uv run python -c "from tunacode.ui.renderers.tools import list_renderers; print(list_renderers())"
|
|
198
|
+
# ['bash', 'glob', 'grep', 'list_dir', 'read_file', 'research_codebase', 'update_file', 'web_fetch', 'write_file']
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Fun Fact:
|
|
202
|
+
We went from 0 syntax-highlighted viewports to 8 in one session. The `update_file` renderer was the lonely pioneer - now it has friends!
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 2026-01-08: The Great Panel Width Debugging Adventure (Branch: master)
|
|
207
|
+
|
|
208
|
+
### The Problem:
|
|
209
|
+
Tool panels were narrower than agent panels. User showed screenshot - `read_file` panel was ~50 chars wide while `agent` panel was full width. Classic NeXTSTEP violation!
|
|
210
|
+
|
|
211
|
+
### The Red Herring (What We Thought):
|
|
212
|
+
Initially believed the issue was `width=TOOL_PANEL_WIDTH` (50 chars) on `Panel()` calls. Spent time:
|
|
213
|
+
- Removing `width=TOOL_PANEL_WIDTH` from 7 Panel() calls in `panels.py`
|
|
214
|
+
- Removing it from `search.py`, `update_file.py`, `app.py`
|
|
215
|
+
- Cleaning up unused imports
|
|
216
|
+
|
|
217
|
+
But panels were STILL narrow after restart. User called me out: "stop being lazy, dig deeper"
|
|
218
|
+
|
|
219
|
+
### The Actual Root Cause (The AHA Moment):
|
|
220
|
+
|
|
221
|
+
**Textual's `RichLog.write()` has its OWN `expand` parameter that defaults to `False`!**
|
|
222
|
+
|
|
223
|
+
From `.venv/lib/python3.13/site-packages/textual/widgets/_rich_log.py`:
|
|
224
|
+
```python
|
|
225
|
+
def write(
|
|
226
|
+
self,
|
|
227
|
+
content: RenderableType | object,
|
|
228
|
+
width: int | None = None,
|
|
229
|
+
expand: bool = False, # <-- THIS IS THE VILLAIN
|
|
230
|
+
shrink: bool = True,
|
|
231
|
+
...
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
When `expand=False` (default), RichLog measures the content's minimum width and renders at that width, **completely ignoring** the Panel's own `expand=True` property!
|
|
236
|
+
|
|
237
|
+
The Panel's expand tells Rich "expand to console width", but RichLog overrides the console width to be just the measured content width. Two different expand flags, two different systems!
|
|
238
|
+
|
|
239
|
+
### The Real Fix:
|
|
240
|
+
Pass `expand=True` to `rich_log.write()`:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# Before
|
|
244
|
+
self.rich_log.write(panel)
|
|
245
|
+
|
|
246
|
+
# After
|
|
247
|
+
self.rich_log.write(panel, expand=True)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Files Modified:
|
|
251
|
+
| File | Change |
|
|
252
|
+
|------|--------|
|
|
253
|
+
| `src/tunacode/ui/app.py` | 3 panel writes → `expand=True` (lines 325, 377, 558) |
|
|
254
|
+
| `src/tunacode/ui/plan_approval.py` | 1 panel write → `expand=True` (line 132) |
|
|
255
|
+
| `src/tunacode/ui/renderers/panels.py` | Removed `width=TOOL_PANEL_WIDTH` (harmless cleanup) |
|
|
256
|
+
| `src/tunacode/ui/renderers/search.py` | Removed unused import |
|
|
257
|
+
| `src/tunacode/ui/renderers/tools/update_file.py` | Removed unused import |
|
|
258
|
+
|
|
259
|
+
### The Lesson:
|
|
260
|
+
When Rich Panel has `expand=True` but isn't expanding in Textual:
|
|
261
|
+
1. The Panel's expand is **not** the issue
|
|
262
|
+
2. Check how the panel is being **written** to the widget
|
|
263
|
+
3. RichLog.write() has its own expand parameter!
|
|
264
|
+
|
|
265
|
+
### Status:
|
|
266
|
+
- Changes made, ruff passes
|
|
267
|
+
- NOT COMMITTED YET - user needs to test
|
|
268
|
+
- Previous width removal changes are technically unnecessary but harmless
|
|
269
|
+
|
|
270
|
+
### Commands:
|
|
271
|
+
```bash
|
|
272
|
+
git diff --stat # See all changes
|
|
273
|
+
uv run ruff check src/tunacode/ui/ # Verify
|
|
274
|
+
# Restart tunacode and make NEW request to test
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Philosophical Note:
|
|
278
|
+
This bug was a perfect example of "the abstraction leaked". Panel.expand and RichLog.write(expand=) look like they should be the same thing, but they operate at different levels. Panel tells Rich what to do. RichLog tells Rich what size canvas to give it. The canvas size wins.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## 2026-01-14: Glob Tool Dead Code Cleanup (Branch: glob-improvements)
|
|
283
|
+
|
|
284
|
+
### The Mission:
|
|
285
|
+
Clean up glob tool based on research doc findings. Remove dead code, fix deprecations.
|
|
286
|
+
|
|
287
|
+
### The Discovery: Semantically Dead Code
|
|
288
|
+
|
|
289
|
+
Static analysis (Vulture) reported "no dead code" in glob.py. But manual review found:
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
# Line 29: Global declared
|
|
293
|
+
_gitignore_patterns: set[str] | None = None
|
|
294
|
+
|
|
295
|
+
# Line 73-74: Function called
|
|
296
|
+
if use_gitignore:
|
|
297
|
+
await _load_gitignore_patterns(root_path)
|
|
298
|
+
|
|
299
|
+
# Lines 155-174: Function populates global
|
|
300
|
+
async def _load_gitignore_patterns(root: Path) -> None:
|
|
301
|
+
global _gitignore_patterns
|
|
302
|
+
# ... reads .gitignore files, populates set
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**The Problem:** `_gitignore_patterns` was NEVER READ. All 7 references were writes. The actual filtering used `DEFAULT_EXCLUDE_DIRS`. The `use_gitignore` parameter was a lie.
|
|
306
|
+
|
|
307
|
+
### Why Vulture Missed It
|
|
308
|
+
|
|
309
|
+
Vulture checks: "Is this symbol referenced?"
|
|
310
|
+
It does NOT check: "Is the result consumed?"
|
|
311
|
+
|
|
312
|
+
The function WAS called. The variable WAS assigned. But the data went nowhere.
|
|
313
|
+
|
|
314
|
+
### Completed:
|
|
315
|
+
|
|
316
|
+
**Commit 61384fe - Dead Code Removal:**
|
|
317
|
+
- Removed `_gitignore_patterns` global
|
|
318
|
+
- Removed `_load_gitignore_patterns()` function (21 lines)
|
|
319
|
+
- Removed `use_gitignore` parameter from signature
|
|
320
|
+
- Replaced 2x `asyncio.get_event_loop().run_in_executor()` with `asyncio.to_thread()`
|
|
321
|
+
- Created QA card: `.claude/qa/semantically-dead-code.md`
|
|
322
|
+
- Added lesson to CLAUDE.md Continuous Learning
|
|
323
|
+
|
|
324
|
+
**Commit 745a56b - Asyncio Deprecation Fixes:**
|
|
325
|
+
Fixed all remaining `get_event_loop()` calls in codebase:
|
|
326
|
+
|
|
327
|
+
| File | Calls | Fix |
|
|
328
|
+
|------|-------|-----|
|
|
329
|
+
| `grep.py` | 2 | `get_running_loop().run_in_executor()` (custom executor) |
|
|
330
|
+
| `startup.py` | 2 | `asyncio.to_thread()` |
|
|
331
|
+
| `app.py` | 2 | `asyncio.to_thread()` |
|
|
332
|
+
| `lsp/client.py` | 3 | `get_running_loop()` for create_future/time |
|
|
333
|
+
|
|
334
|
+
### Key Insight: asyncio.to_thread() vs get_running_loop()
|
|
335
|
+
|
|
336
|
+
- `asyncio.to_thread(func)` - For default executor (None), simpler API
|
|
337
|
+
- `asyncio.get_running_loop().run_in_executor(exec, func)` - For custom executors
|
|
338
|
+
|
|
339
|
+
### Prevention Rule
|
|
340
|
+
|
|
341
|
+
When adding `load_X()` function:
|
|
342
|
+
1. Grep for READS of X, not just references
|
|
343
|
+
2. If a parameter "controls behavior", trace data flow to prove it changes output
|
|
344
|
+
3. Question unused returns - if nothing reads it, why compute it?
|
|
345
|
+
|
|
346
|
+
### Status:
|
|
347
|
+
- Branch: `glob-improvements`
|
|
348
|
+
- Tests: 304 passed
|
|
349
|
+
- Ruff: clean
|
|
350
|
+
- Zero `get_event_loop()` calls remain in src/
|
|
351
|
+
- Ready to push
|
|
352
|
+
|
|
353
|
+
### Next:
|
|
354
|
+
Push branch, optionally create PR
|
|
355
|
+
|
|
356
|
+
### References:
|
|
357
|
+
- Research: `memory-bank/research/2026-01-14_12-27-29_glob-tool-bottlenecks.md`
|
|
358
|
+
- QA Card: `.claude/qa/semantically-dead-code.md`
|
|
359
|
+
- Skill used: `.claude/skills/dead-code-detector/` (Vulture - catches syntactic, not semantic)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Missing cached_tokens in RequestUsage crashes usage tracking
|
|
3
|
+
link: missing-cached-tokens-request-usage
|
|
4
|
+
type: delta
|
|
5
|
+
path: src/tunacode/core/agents/agent_components/orchestrator/usage_tracker.py
|
|
6
|
+
depth: 0
|
|
7
|
+
seams: [D] data
|
|
8
|
+
ontological_relations:
|
|
9
|
+
- relates_to: [[agent-orchestrator]]
|
|
10
|
+
- affects: [[usage-tracking]]
|
|
11
|
+
- fixes: [[requestusage-missing-cached-tokens]]
|
|
12
|
+
tags:
|
|
13
|
+
- usage
|
|
14
|
+
- crash
|
|
15
|
+
- tracking
|
|
16
|
+
created_at: 2026-01-12T22:19:08Z
|
|
17
|
+
updated_at: 2026-01-12T22:19:08Z
|
|
18
|
+
uuid: 00080ff4-9b7e-418b-b7dc-ca671160aee7
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
The new usage tracker accessed `cached_tokens` directly on provider usage objects, which caused an AttributeError for providers that omit that field. We now normalize usage objects at the boundary and default missing fields to 0, matching the old behavior.
|
|
24
|
+
|
|
25
|
+
## Context
|
|
26
|
+
|
|
27
|
+
This surfaced after the node processor refactor when the usage tracking logic moved into `usage_tracker.py` and lost the defensive `getattr` fallback. We missed it because the refactor did not include a regression test for usage objects without cached token data.
|
|
28
|
+
|
|
29
|
+
## Root Cause
|
|
30
|
+
|
|
31
|
+
Provider usage payloads are not uniform: some only include request/response tokens. The new code assumed the presence of `cached_tokens`, violating the implicit contract that missing fields should be treated as zero. Prevention: normalize usage objects at the type boundary and add a test for missing cached tokens.
|
|
32
|
+
|
|
33
|
+
## Changes
|
|
34
|
+
|
|
35
|
+
- Added a normalization helper for usage objects with defaults for missing fields.
|
|
36
|
+
- Updated usage tracking to use the normalized shape.
|
|
37
|
+
- Added a regression test covering missing `cached_tokens`.
|
|
38
|
+
|
|
39
|
+
## Behavioral Impact
|
|
40
|
+
|
|
41
|
+
Usage tracking no longer crashes when a provider omits cached token data; costs and totals still accumulate correctly with cached tokens treated as zero.
|
|
42
|
+
|
|
43
|
+
## Related Cards
|
|
44
|
+
|
|
45
|
+
None
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: list_dir halts agent on bad paths
|
|
3
|
+
link: list-dir-tool-execution-error
|
|
4
|
+
type: delta
|
|
5
|
+
path: src/tunacode/tools/list_dir.py
|
|
6
|
+
depth: 0
|
|
7
|
+
seams: [M] module
|
|
8
|
+
ontological_relations:
|
|
9
|
+
- relates_to: [[tools]]
|
|
10
|
+
- affects: [[tool-executor]]
|
|
11
|
+
- fixes: [[agent-halt-on-tool-error]]
|
|
12
|
+
tags:
|
|
13
|
+
- tools
|
|
14
|
+
- error-handling
|
|
15
|
+
- list_dir
|
|
16
|
+
- ModelRetry
|
|
17
|
+
created_at: 2026-01-07T22:54:00-08:00
|
|
18
|
+
updated_at: 2026-01-07T23:15:00-08:00
|
|
19
|
+
uuid: a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
`list_dir` raised `FileNotFoundError` on non-existent directories, which `@base_tool` wrapped as `ToolExecutionError`. Since `ToolExecutionError` is in `NON_RETRYABLE_ERRORS`, the agent halted instead of letting the LLM self-correct with a valid path.
|
|
25
|
+
|
|
26
|
+
## Context
|
|
27
|
+
|
|
28
|
+
Surfaced when agent called `list_dir("/home/tuna/tunacode/apps")` - a directory that doesn't exist. Agent crashed with `ToolExecutionError` instead of retrying.
|
|
29
|
+
|
|
30
|
+
## Root Cause
|
|
31
|
+
|
|
32
|
+
Error propagation chain:
|
|
33
|
+
1. `list_dir` raises `FileNotFoundError`
|
|
34
|
+
2. `@base_tool` decorator wraps it as `ToolExecutionError`
|
|
35
|
+
3. `tool_executor.py` has `ToolExecutionError` in `NON_RETRYABLE_ERRORS`
|
|
36
|
+
4. Non-retryable errors propagate immediately, halting the agent
|
|
37
|
+
|
|
38
|
+
First attempted fix: switch to `@file_tool` decorator. Failed because `@file_tool` expects required `filepath` positional arg, but `list_dir` has optional `directory="."`.
|
|
39
|
+
|
|
40
|
+
## Changes
|
|
41
|
+
|
|
42
|
+
- Import `ModelRetry` from `pydantic_ai.exceptions`
|
|
43
|
+
- Replace `raise FileNotFoundError(...)` with `raise ModelRetry(...)`
|
|
44
|
+
- Replace `raise NotADirectoryError(...)` with `raise ModelRetry(...)`
|
|
45
|
+
- Keep `@base_tool` decorator (not `@file_tool`)
|
|
46
|
+
|
|
47
|
+
## Behavioral Impact
|
|
48
|
+
|
|
49
|
+
- Agent no longer halts on bad directory paths
|
|
50
|
+
- LLM receives retry signal with error message, can self-correct
|
|
51
|
+
- No change to valid path behavior
|
|
52
|
+
|
|
53
|
+
## Related Cards
|
|
54
|
+
|
|
55
|
+
- [[glob-grep-error-strings]] - similar smell: return error strings instead of raising
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Dangling Tool Calls on User Abort
|
|
3
|
+
link: dangling-tool-calls-abort
|
|
4
|
+
type: delta
|
|
5
|
+
path: src/tunacode/core/agents/main.py
|
|
6
|
+
depth: 0
|
|
7
|
+
seams: [M, S]
|
|
8
|
+
ontological_relations:
|
|
9
|
+
- relates_to: [[conversation-turns]]
|
|
10
|
+
- affects: [[message-history]]
|
|
11
|
+
- fixes: [[api-error-on-next-request]]
|
|
12
|
+
tags:
|
|
13
|
+
- bug
|
|
14
|
+
- abort-handling
|
|
15
|
+
- message-invariants
|
|
16
|
+
- tool-calls
|
|
17
|
+
created_at: 2026-01-17T06:00:00Z
|
|
18
|
+
updated_at: 2026-01-17T06:00:00Z
|
|
19
|
+
uuid: d7c8e9f0-1a2b-3c4d-5e6f-7a8b9c0d1e2f
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# Dangling Tool Calls on User Abort
|
|
23
|
+
|
|
24
|
+
## Summary
|
|
25
|
+
|
|
26
|
+
When a user aborted mid-tool-call (Ctrl+C or tool denial), the conversation history was left with a `ModelResponse` containing tool calls but no corresponding `ToolReturn` messages. The next API request failed because the provider expected tool returns for pending calls.
|
|
27
|
+
|
|
28
|
+
## Context
|
|
29
|
+
|
|
30
|
+
- File: `src/tunacode/core/agents/main.py`
|
|
31
|
+
- PR: #246
|
|
32
|
+
- Surfaces: On any abort during tool execution, next request fails
|
|
33
|
+
|
|
34
|
+
## Root Cause
|
|
35
|
+
|
|
36
|
+
**Missing invariant enforcement on exception path.**
|
|
37
|
+
|
|
38
|
+
The message flow has an implicit invariant:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
INVARIANT: Every ModelResponse with tool_calls MUST be followed by
|
|
42
|
+
matching ToolReturn(s) before the next ModelRequest
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The happy path naturally maintains this - tool executes, result recorded. But `UserAbortError` breaks out of the loop BEFORE recording tool returns, violating the invariant.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
49
|
+
│ Happy Path: │
|
|
50
|
+
│ ModelResponse(tool_calls=[A, B]) │
|
|
51
|
+
│ → execute tools │
|
|
52
|
+
│ → ToolReturn(A), ToolReturn(B) │
|
|
53
|
+
│ → ModelRequest (next turn) ✓ │
|
|
54
|
+
└─────────────────────────────────────────────────────────────┘
|
|
55
|
+
|
|
56
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
57
|
+
│ Abort Path (BEFORE fix): │
|
|
58
|
+
│ ModelResponse(tool_calls=[A, B]) │
|
|
59
|
+
│ → execute tool A │
|
|
60
|
+
│ → UserAbortError raised │
|
|
61
|
+
│ → messages still has ModelResponse with [A, B] │
|
|
62
|
+
│ → NO ToolReturn recorded │
|
|
63
|
+
│ → ModelRequest (next turn) ✗ API ERROR │
|
|
64
|
+
└─────────────────────────────────────────────────────────────┘
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Changes
|
|
68
|
+
|
|
69
|
+
Added `_remove_dangling_tool_calls()` in the `except UserAbortError` handler:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
except UserAbortError:
|
|
73
|
+
cleanup_applied = _remove_dangling_tool_calls(
|
|
74
|
+
self.state_manager.session.messages,
|
|
75
|
+
self.state_manager.session.tool_call_args_by_id,
|
|
76
|
+
)
|
|
77
|
+
if cleanup_applied:
|
|
78
|
+
self.state_manager.session.update_token_count()
|
|
79
|
+
raise
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The function walks backward through messages, removing any trailing `ModelResponse` that has unanswered tool calls, and clears cached args.
|
|
83
|
+
|
|
84
|
+
## Behavioral Impact
|
|
85
|
+
|
|
86
|
+
- User aborts mid-tool → dangling messages cleaned up
|
|
87
|
+
- Next request works normally
|
|
88
|
+
- Token count recalculated after cleanup
|
|
89
|
+
|
|
90
|
+
## Prevention: What We Should Have Done
|
|
91
|
+
|
|
92
|
+
### 1. Document Message Invariants
|
|
93
|
+
|
|
94
|
+
The conversation turns doc now exists, but we missed documenting this invariant:
|
|
95
|
+
|
|
96
|
+
```markdown
|
|
97
|
+
## Message Invariants
|
|
98
|
+
|
|
99
|
+
1. **Tool Call Pairing**: Every `ModelResponse` with tool_calls MUST
|
|
100
|
+
be followed by matching `ToolReturn(s)` before any new `ModelRequest`.
|
|
101
|
+
|
|
102
|
+
2. **Exception Safety**: Any exception path that exits the agent loop
|
|
103
|
+
must restore message history to a valid state.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Add this to `docs/codebase-map/architecture/conversation-turns.md`.
|
|
107
|
+
|
|
108
|
+
### 2. Add Exception Path Tests
|
|
109
|
+
|
|
110
|
+
No test existed for abort scenarios:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
async def test_abort_mid_tool_call_cleans_up_messages():
|
|
114
|
+
"""Verify abort during tool execution doesn't corrupt message history."""
|
|
115
|
+
# Arrange: Start a request that will trigger a tool call
|
|
116
|
+
# Act: Raise UserAbortError during tool execution
|
|
117
|
+
# Assert: messages ends with a valid state (no dangling tool calls)
|
|
118
|
+
# Assert: Next request succeeds
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. State Machine Should Track Message Validity
|
|
122
|
+
|
|
123
|
+
The `ResponseState` tracks iteration progress but not message-level invariants. Consider:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
def validate_message_invariants(messages: list[Any]) -> bool:
|
|
127
|
+
"""Return False if messages violate tool-call pairing invariant."""
|
|
128
|
+
# Walk through messages
|
|
129
|
+
# Track pending tool calls
|
|
130
|
+
# Verify each is answered before next ModelRequest
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This could be called:
|
|
134
|
+
- After each agent iteration (debug mode)
|
|
135
|
+
- Before persisting session
|
|
136
|
+
- On session load
|
|
137
|
+
|
|
138
|
+
### 4. Design Pattern: Exception-Safe State Updates
|
|
139
|
+
|
|
140
|
+
The broader lesson: **state mutations during a loop must be exception-safe**.
|
|
141
|
+
|
|
142
|
+
Options:
|
|
143
|
+
1. **Rollback on exception** (what we did) - detect and fix invalid state
|
|
144
|
+
2. **Transactional updates** - only commit state after successful completion
|
|
145
|
+
3. **Copy-on-write** - work on a copy, swap on success
|
|
146
|
+
|
|
147
|
+
For message history, option 2 would be:
|
|
148
|
+
```python
|
|
149
|
+
# Don't append to session.messages during the loop
|
|
150
|
+
# Collect in a local buffer
|
|
151
|
+
# Merge to session.messages only on successful completion
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
This is partially what `agent_run.all_messages()` does - but the exception path didn't use it.
|
|
155
|
+
|
|
156
|
+
## Related Cards
|
|
157
|
+
|
|
158
|
+
- [[conversation-turns]] - Full turn flow documentation
|
|
159
|
+
- [[message-history-persistence]] - How messages are persisted
|
|
160
|
+
- [[response-state]] - State machine for agent progress
|
|
161
|
+
|
|
162
|
+
## Lesson
|
|
163
|
+
|
|
164
|
+
**Exception paths are first-class citizens.** When designing a stateful loop:
|
|
165
|
+
|
|
166
|
+
1. List every exception that can exit the loop
|
|
167
|
+
2. For each: what state is left behind?
|
|
168
|
+
3. For each: is that state valid for the next operation?
|
|
169
|
+
4. Add tests for exception scenarios
|
|
170
|
+
|
|
171
|
+
The bug was obvious in hindsight - we just never traced what happens when `UserAbortError` interrupts the tool execution flow.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Remove global cache state from user_configuration
|
|
3
|
+
link: delta/remove-global-cache-user-config
|
|
4
|
+
type: delta
|
|
5
|
+
path: src/tunacode/utils/config/user_configuration.py
|
|
6
|
+
depth: 3
|
|
7
|
+
seams: [M] module
|
|
8
|
+
ontological_relations:
|
|
9
|
+
- relates_to: [[utils]]
|
|
10
|
+
- affects: [[user_configuration.py]]
|
|
11
|
+
tags:
|
|
12
|
+
- utils
|
|
13
|
+
- config
|
|
14
|
+
- state-management
|
|
15
|
+
- cleanup
|
|
16
|
+
created_at: 2026-01-12T00:00:00Z
|
|
17
|
+
updated_at: 2026-01-12T00:00:00Z
|
|
18
|
+
uuid: 3383a720-0203-4a5b-9c1c-7b2f8c4d5e6f
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
Removed global mutable cache state from the user configuration module. The previous implementation used module-level `_config_fingerprint` and `_config_cache` variables for a fast-path optimization that was likely premature for configuration file handling.
|
|
24
|
+
|
|
25
|
+
## Context
|
|
26
|
+
|
|
27
|
+
The original `load_config()` function stored parsed config and its SHA-1 fingerprint in module globals to avoid re-parsing unchanged files. This added complexity and hidden state that could cause cache staleness issues.
|
|
28
|
+
|
|
29
|
+
## Root Cause
|
|
30
|
+
|
|
31
|
+
The fast-path optimization was unnecessary overhead for configuration files that:
|
|
32
|
+
- Are small (typically < 1KB)
|
|
33
|
+
- Are read infrequently (once per session or on demand)
|
|
34
|
+
- May change externally between calls
|
|
35
|
+
|
|
36
|
+
The cost of hashing and comparing fingerprints likely exceeded the cost of simply parsing the JSON.
|
|
37
|
+
|
|
38
|
+
## Changes
|
|
39
|
+
|
|
40
|
+
- Removed `_config_fingerprint` and `_config_cache` module-level globals
|
|
41
|
+
- Simplified `load_config()` to read and parse file directly
|
|
42
|
+
- Changed `save_config()` return type from `bool` to `None` (always returned `True`)
|
|
43
|
+
- Changed `set_default_model()` return type from `bool` to `None`
|
|
44
|
+
- Removed dead `except ConfigurationError: raise` code in `set_default_model()`
|
|
45
|
+
|
|
46
|
+
## Behavioral Impact
|
|
47
|
+
|
|
48
|
+
- Config loading is now simpler and more predictable
|
|
49
|
+
- No functional change in behavior - callers already handled `None` returns and exceptions
|
|
50
|
+
- Slightly more straightforward debugging with no hidden cache state
|
|
51
|
+
|
|
52
|
+
## Related Cards
|
|
53
|
+
|
|
54
|
+
- [[utils]] - Parent system
|