tunacode-cli 0.0.36__tar.gz → 0.0.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.
Potentially problematic release.
This version of tunacode-cli might be problematic. Click here for more details.
- {tunacode_cli-0.0.36/src/tunacode_cli.egg-info → tunacode_cli-0.0.37}/PKG-INFO +17 -17
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/README.md +16 -14
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/pyproject.toml +24 -8
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/setup.py +1 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/__init__.py +2 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/system.py +39 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/registry.py +8 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/repl.py +91 -30
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/constants.py +1 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/agents/main.py +41 -1
- tunacode_cli-0.0.37/src/tunacode/core/agents/utils.py +304 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/config_setup.py +0 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/state.py +4 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/console.py +4 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/panels.py +74 -0
- tunacode_cli-0.0.37/src/tunacode/ui/utils.py +3 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37/src/tunacode_cli.egg-info}/PKG-INFO +17 -17
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode_cli.egg-info/SOURCES.txt +4 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode_cli.egg-info/requires.txt +1 -3
- tunacode_cli-0.0.37/tests/characterization/agent/__init__.py +1 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/conftest.py +8 -5
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/test_agent_creation.py +84 -66
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/test_json_tool_parsing.py +57 -59
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/test_process_node.py +115 -79
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/test_process_request.py +112 -104
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/agent/test_tool_message_patching.py +59 -54
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/background/test_background_edge_cases.py +18 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/background/test_cleanup.py +11 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/background/test_task_cancellation.py +9 -3
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/background/test_task_creation.py +7 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/background/test_task_execution.py +7 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/code_index/test_cache_management.py +8 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/code_index/test_file_scanning.py +9 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/code_index/test_index_building.py +15 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/code_index/test_search_operations.py +11 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/code_index/test_symbol_extraction.py +11 -5
- tunacode_cli-0.0.37/tests/characterization/commands/__init__.py +1 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/commands/test_init_command.py +63 -67
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/conftest.py +24 -4
- tunacode_cli-0.0.37/tests/characterization/context/__init__.py +1 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/context/test_context_acceptance.py +14 -16
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/context/test_context_integration.py +15 -16
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/context/test_context_loading.py +27 -28
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/context/test_tunacode_logging.py +15 -16
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_command_parsing.py +27 -17
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_input_handling.py +24 -17
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_keyboard_interrupts.py +17 -12
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_multiline_input.py +17 -12
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_repl_initialization.py +14 -10
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/repl/test_session_flow.py +34 -22
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/services/test_error_recovery.py +13 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/services/test_llm_routing.py +13 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/services/test_mcp_integration.py +13 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/services/test_service_lifecycle.py +13 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_agent_tracking.py +5 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_message_history.py +6 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_permissions.py +5 -3
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_session_management.py +5 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_state_initialization.py +7 -3
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/state/test_user_config.py +5 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/test_characterization_commands.py +75 -68
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/ui/test_async_ui.py +7 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/ui/test_console_output.py +7 -5
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/ui/test_diff_display.py +4 -3
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/ui/test_prompt_rendering.py +7 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/ui/test_tool_confirmations.py +6 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/utils/test_file_operations.py +11 -7
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/utils/test_git_commands.py +32 -6
- tunacode_cli-0.0.37/tests/characterization/utils/test_token_counting.py +39 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/characterization/utils/test_utils_edge_cases.py +18 -7
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/conftest.py +109 -52
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/crud/test_core_file_operations.py +87 -71
- tunacode_cli-0.0.37/tests/fixtures/__init__.py +1 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/fixtures/file_operations.py +97 -78
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/integration/test_error_recovery_flow.py +4 -2
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/integration/test_full_session_flow.py +9 -9
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/integration/test_mcp_tool_flow.py +13 -16
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/integration/test_multi_tool_operations.py +4 -5
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/integration/test_performance_scenarios.py +8 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_actual_parallelism.py +72 -65
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_agent_initialization.py +53 -48
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_background_manager.py +5 -4
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_agent_main.py +15 -10
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_bash.py +49 -49
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_commands_system.py +32 -14
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_glob.py +79 -75
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_grep.py +83 -68
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_grep_performance.py +75 -66
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_iteration_limits.py +25 -29
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_list_dir.py +62 -56
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_read_file.py +48 -45
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_repl_utils.py +15 -10
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_run_command.py +50 -46
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_setup_system.py +18 -11
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_tool_ui_behavior.py +37 -29
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_update_file.py +64 -101
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_utilities.py +26 -20
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_characterization_write_file.py +50 -46
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_cli_command_flow.py +102 -119
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_cli_file_operations_integration.py +73 -75
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_config_directory_creation.py +15 -15
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_config_setup_async.py +44 -33
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_enhanced_visual_feedback.py +20 -15
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_fallback_responses.py +13 -5
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_fast_glob_search.py +55 -43
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_file_operations_edge_cases.py +94 -86
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_file_operations_stress.py +81 -77
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_file_reference_context_tracking.py +27 -28
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_file_reference_expansion.py +34 -32
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_grep_fast_glob.py +63 -68
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_grep_legacy_compat.py +6 -7
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_grep_timeout.py +71 -69
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_json_tool_parsing.py +57 -54
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_list_dir.py +27 -26
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_parallel_execution_demo.py +33 -31
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_parallel_execution_freeze_fix.py +28 -27
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_parallel_execution_integration.py +48 -40
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_parallel_read_only_tools.py +90 -64
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_parallel_tool_execution.py +31 -29
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_read_only_confirmation.py +14 -14
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_security.py +49 -45
- tunacode_cli-0.0.37/tests/test_streaming_panel_tool_confirmation.py +176 -0
- tunacode_cli-0.0.37/tests/test_streaming_spinner_conflict.py +129 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_tool_categorization.py +23 -24
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_tool_combinations.py +143 -121
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_tool_handler_ui_messages.py +43 -29
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_update_command.py +6 -5
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/tests/test_visual_parallel_feedback.py +50 -38
- tunacode_cli-0.0.36/tests/characterization/agent/__init__.py +0 -1
- tunacode_cli-0.0.36/tests/characterization/commands/__init__.py +0 -1
- tunacode_cli-0.0.36/tests/characterization/context/__init__.py +0 -1
- tunacode_cli-0.0.36/tests/characterization/utils/test_token_counting.py +0 -29
- tunacode_cli-0.0.36/tests/fixtures/__init__.py +0 -1
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/CLAUDE.md +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/LICENSE +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/MANIFEST.in +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/TUNACODE.md +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/setup.cfg +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/base.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/conversation.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/debug.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/development.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/model.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/main.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/textual_app.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/textual_bridge.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/configuration/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/configuration/defaults.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/configuration/models.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/configuration/settings.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/context.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/agents/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/background/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/background/manager.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/code_index.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/llm/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/agent_setup.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/base.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/coordinator.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/environment_setup.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/setup/git_safety_setup.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/core/tool_handler.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/exceptions.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/prompts/system.md +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/py.typed +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/services/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/services/mcp.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/setup.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/base.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/bash.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/glob.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/grep.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/list_dir.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/read_file.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/read_file_async_poc.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/run_command.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/update_file.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/tools/write_file.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/types.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/completers.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/constants.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/decorators.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/input.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/keybindings.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/lexers.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/output.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/prompt_manager.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/tool_ui.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/ui/validators.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/__init__.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/bm25.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/diff_utils.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/file_utils.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/import_cache.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/ripgrep.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/security.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/system.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/text_utils.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/token_counter.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/utils/user_configuration.py +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
- {tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunacode-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.37
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,9 +26,7 @@ Requires-Dist: pygments==2.19.1
|
|
|
26
26
|
Requires-Dist: rich==14.0.0
|
|
27
27
|
Provides-Extra: dev
|
|
28
28
|
Requires-Dist: build; extra == "dev"
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist: flake8; extra == "dev"
|
|
31
|
-
Requires-Dist: isort; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff; extra == "dev"
|
|
32
30
|
Requires-Dist: pytest; extra == "dev"
|
|
33
31
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
32
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
@@ -70,7 +68,7 @@ Choose your AI provider and set your API key:
|
|
|
70
68
|
# OpenAI
|
|
71
69
|
tunacode --model "openai:gpt-4o" --key "sk-your-openai-key"
|
|
72
70
|
|
|
73
|
-
# Anthropic Claude
|
|
71
|
+
# Anthropic Claude
|
|
74
72
|
tunacode --model "anthropic:claude-3.5-sonnet" --key "sk-ant-your-anthropic-key"
|
|
75
73
|
|
|
76
74
|
# OpenRouter (100+ models)
|
|
@@ -82,13 +80,14 @@ Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.c
|
|
|
82
80
|
### Recommended Models
|
|
83
81
|
|
|
84
82
|
Based on extensive testing, these models provide the best performance:
|
|
83
|
+
|
|
85
84
|
- `google/gemini-2.5-pro` - Excellent for complex reasoning
|
|
86
85
|
- `openai/gpt-4.1` - Strong general-purpose model
|
|
87
86
|
- `deepseek/deepseek-r1-0528` - Great for code generation
|
|
88
87
|
- `openai/gpt-4.1-mini` - Fast and cost-effective
|
|
89
88
|
- `anthropic/claude-4-sonnet-20250522` - Superior context handling
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
_Note: Formal evaluations coming soon. Any model can work, but these have shown the best results in practice._
|
|
92
91
|
|
|
93
92
|
## Start Coding
|
|
94
93
|
|
|
@@ -98,16 +97,16 @@ tunacode
|
|
|
98
97
|
|
|
99
98
|
## Basic Commands
|
|
100
99
|
|
|
101
|
-
| Command
|
|
102
|
-
|
|
|
103
|
-
| `/help`
|
|
104
|
-
| `/model <provider:name>` | Switch model
|
|
105
|
-
| `/clear`
|
|
106
|
-
| `/compact`
|
|
107
|
-
| `/branch <name>`
|
|
108
|
-
| `/yolo`
|
|
109
|
-
| `!<command>`
|
|
110
|
-
| `exit`
|
|
100
|
+
| Command | Description |
|
|
101
|
+
| ------------------------ | ---------------------- |
|
|
102
|
+
| `/help` | Show all commands |
|
|
103
|
+
| `/model <provider:name>` | Switch model |
|
|
104
|
+
| `/clear` | Clear message history |
|
|
105
|
+
| `/compact` | Summarize conversation |
|
|
106
|
+
| `/branch <name>` | Create Git branch |
|
|
107
|
+
| `/yolo` | Skip confirmations |
|
|
108
|
+
| `!<command>` | Run shell command |
|
|
109
|
+
| `exit` | Exit TunaCode |
|
|
111
110
|
|
|
112
111
|
## Performance
|
|
113
112
|
|
|
@@ -122,11 +121,12 @@ Multiple file reads, directory listings, and searches execute concurrently using
|
|
|
122
121
|
- **Streaming UI**: Currently working on implementing streaming responses for better user experience
|
|
123
122
|
- **Bug Fixes**: Actively addressing issues - please report any bugs you encounter!
|
|
124
123
|
|
|
125
|
-
|
|
124
|
+
_Note: While the tool is fully functional, we're focusing on stability and core features before optimizing for speed._
|
|
126
125
|
|
|
127
126
|
## Safety First
|
|
128
127
|
|
|
129
128
|
⚠️ **Important**: TunaCode can modify your codebase. Always:
|
|
129
|
+
|
|
130
130
|
- Use Git branches before making changes
|
|
131
131
|
- Review file modifications before confirming
|
|
132
132
|
- Keep backups of important work
|
|
@@ -33,7 +33,7 @@ Choose your AI provider and set your API key:
|
|
|
33
33
|
# OpenAI
|
|
34
34
|
tunacode --model "openai:gpt-4o" --key "sk-your-openai-key"
|
|
35
35
|
|
|
36
|
-
# Anthropic Claude
|
|
36
|
+
# Anthropic Claude
|
|
37
37
|
tunacode --model "anthropic:claude-3.5-sonnet" --key "sk-ant-your-anthropic-key"
|
|
38
38
|
|
|
39
39
|
# OpenRouter (100+ models)
|
|
@@ -45,13 +45,14 @@ Your config is saved to `~/.config/tunacode.json` (edit directly with `nvim ~/.c
|
|
|
45
45
|
### Recommended Models
|
|
46
46
|
|
|
47
47
|
Based on extensive testing, these models provide the best performance:
|
|
48
|
+
|
|
48
49
|
- `google/gemini-2.5-pro` - Excellent for complex reasoning
|
|
49
50
|
- `openai/gpt-4.1` - Strong general-purpose model
|
|
50
51
|
- `deepseek/deepseek-r1-0528` - Great for code generation
|
|
51
52
|
- `openai/gpt-4.1-mini` - Fast and cost-effective
|
|
52
53
|
- `anthropic/claude-4-sonnet-20250522` - Superior context handling
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
_Note: Formal evaluations coming soon. Any model can work, but these have shown the best results in practice._
|
|
55
56
|
|
|
56
57
|
## Start Coding
|
|
57
58
|
|
|
@@ -61,16 +62,16 @@ tunacode
|
|
|
61
62
|
|
|
62
63
|
## Basic Commands
|
|
63
64
|
|
|
64
|
-
| Command
|
|
65
|
-
|
|
|
66
|
-
| `/help`
|
|
67
|
-
| `/model <provider:name>` | Switch model
|
|
68
|
-
| `/clear`
|
|
69
|
-
| `/compact`
|
|
70
|
-
| `/branch <name>`
|
|
71
|
-
| `/yolo`
|
|
72
|
-
| `!<command>`
|
|
73
|
-
| `exit`
|
|
65
|
+
| Command | Description |
|
|
66
|
+
| ------------------------ | ---------------------- |
|
|
67
|
+
| `/help` | Show all commands |
|
|
68
|
+
| `/model <provider:name>` | Switch model |
|
|
69
|
+
| `/clear` | Clear message history |
|
|
70
|
+
| `/compact` | Summarize conversation |
|
|
71
|
+
| `/branch <name>` | Create Git branch |
|
|
72
|
+
| `/yolo` | Skip confirmations |
|
|
73
|
+
| `!<command>` | Run shell command |
|
|
74
|
+
| `exit` | Exit TunaCode |
|
|
74
75
|
|
|
75
76
|
## Performance
|
|
76
77
|
|
|
@@ -85,11 +86,12 @@ Multiple file reads, directory listings, and searches execute concurrently using
|
|
|
85
86
|
- **Streaming UI**: Currently working on implementing streaming responses for better user experience
|
|
86
87
|
- **Bug Fixes**: Actively addressing issues - please report any bugs you encounter!
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
_Note: While the tool is fully functional, we're focusing on stability and core features before optimizing for speed._
|
|
89
90
|
|
|
90
91
|
## Safety First
|
|
91
92
|
|
|
92
93
|
⚠️ **Important**: TunaCode can modify your codebase. Always:
|
|
94
|
+
|
|
93
95
|
- Use Git branches before making changes
|
|
94
96
|
- Review file modifications before confirming
|
|
95
97
|
- Keep backups of important work
|
|
@@ -109,4 +111,4 @@ Multiple file reads, directory listings, and searches execute concurrently using
|
|
|
109
111
|
|
|
110
112
|
---
|
|
111
113
|
|
|
112
|
-
MIT License - see [LICENSE](LICENSE) file
|
|
114
|
+
MIT License - see [LICENSE](LICENSE) file
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tunacode-cli"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.37"
|
|
8
8
|
description = "Your agentic CLI developer."
|
|
9
9
|
keywords = ["cli", "agent", "development", "automation"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -38,9 +38,7 @@ tunacode = "tunacode.cli.main:app"
|
|
|
38
38
|
[project.optional-dependencies]
|
|
39
39
|
dev = [
|
|
40
40
|
"build",
|
|
41
|
-
"
|
|
42
|
-
"flake8",
|
|
43
|
-
"isort",
|
|
41
|
+
"ruff",
|
|
44
42
|
"pytest",
|
|
45
43
|
"pytest-cov",
|
|
46
44
|
"pytest-asyncio",
|
|
@@ -51,9 +49,27 @@ dev = [
|
|
|
51
49
|
Homepage = "https://github.com/larock22/tunacode"
|
|
52
50
|
Repository = "https://github.com/larock22/tunacode"
|
|
53
51
|
|
|
54
|
-
[tool.
|
|
52
|
+
[tool.ruff]
|
|
55
53
|
line-length = 100
|
|
56
54
|
|
|
57
|
-
[tool.
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
[tool.ruff.lint]
|
|
56
|
+
extend-select = ["I"]
|
|
57
|
+
ignore = ["E203", "E501"]
|
|
58
|
+
exclude = [
|
|
59
|
+
".bzr",
|
|
60
|
+
".direnv",
|
|
61
|
+
".eggs",
|
|
62
|
+
".git",
|
|
63
|
+
".hg",
|
|
64
|
+
".mypy_cache",
|
|
65
|
+
".nox",
|
|
66
|
+
".pants.d",
|
|
67
|
+
".ruff_cache",
|
|
68
|
+
".svn",
|
|
69
|
+
".tox",
|
|
70
|
+
".venv",
|
|
71
|
+
"__pypackages__",
|
|
72
|
+
"build",
|
|
73
|
+
"dist",
|
|
74
|
+
"venv",
|
|
75
|
+
]
|
{tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/__init__.py
RENAMED
|
@@ -12,13 +12,14 @@ from .debug import (
|
|
|
12
12
|
)
|
|
13
13
|
from .development import BranchCommand, InitCommand
|
|
14
14
|
from .model import ModelCommand
|
|
15
|
-
from .system import ClearCommand, HelpCommand, RefreshConfigCommand, UpdateCommand
|
|
15
|
+
from .system import ClearCommand, HelpCommand, RefreshConfigCommand, StreamingCommand, UpdateCommand
|
|
16
16
|
|
|
17
17
|
__all__ = [
|
|
18
18
|
# System commands
|
|
19
19
|
"HelpCommand",
|
|
20
20
|
"ClearCommand",
|
|
21
21
|
"RefreshConfigCommand",
|
|
22
|
+
"StreamingCommand",
|
|
22
23
|
"UpdateCommand",
|
|
23
24
|
# Debug commands
|
|
24
25
|
"YoloCommand",
|
{tunacode_cli-0.0.36 → tunacode_cli-0.0.37}/src/tunacode/cli/commands/implementations/system.py
RENAMED
|
@@ -175,3 +175,42 @@ class UpdateCommand(SimpleCommand):
|
|
|
175
175
|
await ui.error(f"Update failed: {e}")
|
|
176
176
|
except FileNotFoundError:
|
|
177
177
|
await ui.error(f"Could not find {installation_method} executable")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class StreamingCommand(SimpleCommand):
|
|
181
|
+
"""Toggle streaming display on/off."""
|
|
182
|
+
|
|
183
|
+
spec = CommandSpec(
|
|
184
|
+
name="streaming",
|
|
185
|
+
aliases=["/streaming"],
|
|
186
|
+
description="Toggle streaming display on/off",
|
|
187
|
+
category=CommandCategory.SYSTEM,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
async def execute(self, args: List[str], context: CommandContext) -> None:
|
|
191
|
+
current_setting = context.state_manager.session.user_config.get("settings", {}).get(
|
|
192
|
+
"enable_streaming", True
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
if args and args[0].lower() in ["on", "true", "1", "enable", "enabled"]:
|
|
196
|
+
new_setting = True
|
|
197
|
+
elif args and args[0].lower() in ["off", "false", "0", "disable", "disabled"]:
|
|
198
|
+
new_setting = False
|
|
199
|
+
else:
|
|
200
|
+
# Toggle current setting
|
|
201
|
+
new_setting = not current_setting
|
|
202
|
+
|
|
203
|
+
# Update the configuration
|
|
204
|
+
if "settings" not in context.state_manager.session.user_config:
|
|
205
|
+
context.state_manager.session.user_config["settings"] = {}
|
|
206
|
+
context.state_manager.session.user_config["settings"]["enable_streaming"] = new_setting
|
|
207
|
+
|
|
208
|
+
status = "enabled" if new_setting else "disabled"
|
|
209
|
+
await ui.success(f"Streaming display {status}")
|
|
210
|
+
|
|
211
|
+
if new_setting:
|
|
212
|
+
await ui.muted(
|
|
213
|
+
"Responses will be displayed progressively as they are generated (default)"
|
|
214
|
+
)
|
|
215
|
+
else:
|
|
216
|
+
await ui.muted("Responses will be displayed all at once after completion")
|
|
@@ -19,7 +19,13 @@ from .implementations.debug import (
|
|
|
19
19
|
)
|
|
20
20
|
from .implementations.development import BranchCommand, InitCommand
|
|
21
21
|
from .implementations.model import ModelCommand
|
|
22
|
-
from .implementations.system import
|
|
22
|
+
from .implementations.system import (
|
|
23
|
+
ClearCommand,
|
|
24
|
+
HelpCommand,
|
|
25
|
+
RefreshConfigCommand,
|
|
26
|
+
StreamingCommand,
|
|
27
|
+
UpdateCommand,
|
|
28
|
+
)
|
|
23
29
|
|
|
24
30
|
|
|
25
31
|
@dataclass
|
|
@@ -106,6 +112,7 @@ class CommandRegistry:
|
|
|
106
112
|
FixCommand,
|
|
107
113
|
ParseToolsCommand,
|
|
108
114
|
RefreshConfigCommand,
|
|
115
|
+
StreamingCommand,
|
|
109
116
|
UpdateCommand,
|
|
110
117
|
HelpCommand,
|
|
111
118
|
BranchCommand,
|
|
@@ -70,8 +70,9 @@ async def _tool_confirm(tool_call, node, state_manager: StateManager):
|
|
|
70
70
|
await _tool_ui.log_mcp(title, args)
|
|
71
71
|
return
|
|
72
72
|
|
|
73
|
-
# Stop spinner during user interaction
|
|
74
|
-
state_manager.session.spinner
|
|
73
|
+
# Stop spinner during user interaction (only if not streaming)
|
|
74
|
+
if not state_manager.session.is_streaming_active and state_manager.session.spinner:
|
|
75
|
+
state_manager.session.spinner.stop()
|
|
75
76
|
|
|
76
77
|
# Create confirmation request
|
|
77
78
|
request = tool_handler.create_confirmation_request(tool_call.tool_name, args)
|
|
@@ -84,7 +85,10 @@ async def _tool_confirm(tool_call, node, state_manager: StateManager):
|
|
|
84
85
|
raise UserAbortError("User aborted.")
|
|
85
86
|
|
|
86
87
|
await ui.line() # Add line after user input
|
|
87
|
-
|
|
88
|
+
|
|
89
|
+
# Restart spinner (only if not streaming)
|
|
90
|
+
if not state_manager.session.is_streaming_active and state_manager.session.spinner:
|
|
91
|
+
state_manager.session.spinner.start()
|
|
88
92
|
|
|
89
93
|
|
|
90
94
|
async def _tool_handler(part, node, state_manager: StateManager):
|
|
@@ -96,7 +100,19 @@ async def _tool_handler(part, node, state_manager: StateManager):
|
|
|
96
100
|
if tool_handler.should_confirm(part.tool_name):
|
|
97
101
|
await ui.info(f"Tool({part.tool_name})")
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
# Stop spinner only if not streaming
|
|
104
|
+
if not state_manager.session.is_streaming_active and state_manager.session.spinner:
|
|
105
|
+
state_manager.session.spinner.stop()
|
|
106
|
+
|
|
107
|
+
# Track if we need to stop/restart streaming panel
|
|
108
|
+
streaming_panel = None
|
|
109
|
+
if state_manager.session.is_streaming_active and hasattr(
|
|
110
|
+
state_manager.session, "streaming_panel"
|
|
111
|
+
):
|
|
112
|
+
streaming_panel = state_manager.session.streaming_panel
|
|
113
|
+
# Stop the streaming panel to prevent UI interference during confirmation
|
|
114
|
+
if streaming_panel and tool_handler.should_confirm(part.tool_name):
|
|
115
|
+
await streaming_panel.stop()
|
|
100
116
|
|
|
101
117
|
try:
|
|
102
118
|
args = _parse_args(part.args)
|
|
@@ -128,7 +144,13 @@ async def _tool_handler(part, node, state_manager: StateManager):
|
|
|
128
144
|
patch_tool_messages("Operation aborted by user.", state_manager)
|
|
129
145
|
raise
|
|
130
146
|
finally:
|
|
131
|
-
|
|
147
|
+
# Restart streaming panel if it was stopped
|
|
148
|
+
if streaming_panel and tool_handler.should_confirm(part.tool_name):
|
|
149
|
+
await streaming_panel.start()
|
|
150
|
+
|
|
151
|
+
# Restart spinner only if not streaming
|
|
152
|
+
if not state_manager.session.is_streaming_active and state_manager.session.spinner:
|
|
153
|
+
state_manager.session.spinner.start()
|
|
132
154
|
|
|
133
155
|
|
|
134
156
|
# Initialize command registry
|
|
@@ -195,38 +217,77 @@ async def process_request(text: str, state_manager: StateManager, output: bool =
|
|
|
195
217
|
await ui.error(str(e))
|
|
196
218
|
return
|
|
197
219
|
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
text,
|
|
202
|
-
state_manager,
|
|
203
|
-
tool_callback=tool_callback_with_state,
|
|
220
|
+
# Check if streaming is enabled (default: True for better UX)
|
|
221
|
+
enable_streaming = state_manager.session.user_config.get("settings", {}).get(
|
|
222
|
+
"enable_streaming", True
|
|
204
223
|
)
|
|
224
|
+
|
|
225
|
+
if enable_streaming:
|
|
226
|
+
# Stop spinner before starting streaming display (Rich.Live conflict)
|
|
227
|
+
await ui.spinner(False, state_manager.session.spinner, state_manager)
|
|
228
|
+
|
|
229
|
+
# Mark that streaming is active to prevent spinner conflicts
|
|
230
|
+
state_manager.session.is_streaming_active = True
|
|
231
|
+
|
|
232
|
+
# Use streaming agent processing
|
|
233
|
+
streaming_panel = ui.StreamingAgentPanel()
|
|
234
|
+
await streaming_panel.start()
|
|
235
|
+
|
|
236
|
+
# Store streaming panel reference in session for tool handler access
|
|
237
|
+
state_manager.session.streaming_panel = streaming_panel
|
|
238
|
+
|
|
239
|
+
try:
|
|
240
|
+
|
|
241
|
+
async def streaming_callback(content: str):
|
|
242
|
+
await streaming_panel.update(content)
|
|
243
|
+
|
|
244
|
+
res = await agent.process_request(
|
|
245
|
+
state_manager.session.current_model,
|
|
246
|
+
text,
|
|
247
|
+
state_manager,
|
|
248
|
+
tool_callback=tool_callback_with_state,
|
|
249
|
+
streaming_callback=streaming_callback,
|
|
250
|
+
)
|
|
251
|
+
finally:
|
|
252
|
+
await streaming_panel.stop()
|
|
253
|
+
# Clear streaming panel reference
|
|
254
|
+
state_manager.session.streaming_panel = None
|
|
255
|
+
# Mark streaming as inactive
|
|
256
|
+
state_manager.session.is_streaming_active = False
|
|
257
|
+
# Don't restart spinner - it will be stopped in the outer finally block anyway
|
|
258
|
+
else:
|
|
259
|
+
# Use normal agent processing
|
|
260
|
+
res = await agent.process_request(
|
|
261
|
+
state_manager.session.current_model,
|
|
262
|
+
text,
|
|
263
|
+
state_manager,
|
|
264
|
+
tool_callback=tool_callback_with_state,
|
|
265
|
+
)
|
|
205
266
|
if output:
|
|
206
267
|
if state_manager.session.show_thoughts:
|
|
207
268
|
new_msgs = state_manager.session.messages[start_idx:]
|
|
208
269
|
for msg in new_msgs:
|
|
209
270
|
if isinstance(msg, dict) and "thought" in msg:
|
|
210
271
|
await ui.muted(f"THOUGHT: {msg['thought']}")
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
await ui.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
272
|
+
|
|
273
|
+
# Only display result if not streaming (streaming already showed content)
|
|
274
|
+
if not enable_streaming:
|
|
275
|
+
# Check if result exists and has output
|
|
276
|
+
if (
|
|
277
|
+
hasattr(res, "result")
|
|
278
|
+
and res.result is not None
|
|
279
|
+
and hasattr(res.result, "output")
|
|
280
|
+
):
|
|
281
|
+
await ui.agent(res.result.output)
|
|
282
|
+
else:
|
|
283
|
+
# Fallback: show that the request was processed
|
|
284
|
+
await ui.muted("Request completed")
|
|
285
|
+
|
|
286
|
+
# Always show files in context after agent response
|
|
287
|
+
if state_manager.session.files_in_context:
|
|
288
|
+
# Extract just filenames from full paths for readability
|
|
289
|
+
filenames = [Path(f).name for f in sorted(state_manager.session.files_in_context)]
|
|
290
|
+
await ui.muted(f"\nFiles in context: {', '.join(filenames)}")
|
|
230
291
|
except CancelledError:
|
|
231
292
|
await ui.muted("Request cancelled")
|
|
232
293
|
except UserAbortError:
|
|
@@ -12,6 +12,22 @@ from datetime import datetime, timezone
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Any, Iterator, List, Optional, Tuple
|
|
14
14
|
|
|
15
|
+
from pydantic_ai import Agent
|
|
16
|
+
|
|
17
|
+
# Import streaming types with fallback for older versions
|
|
18
|
+
try:
|
|
19
|
+
from pydantic_ai.messages import (
|
|
20
|
+
PartDeltaEvent,
|
|
21
|
+
TextPartDelta,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
STREAMING_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
# Fallback for older pydantic-ai versions
|
|
27
|
+
PartDeltaEvent = None
|
|
28
|
+
TextPartDelta = None
|
|
29
|
+
STREAMING_AVAILABLE = False
|
|
30
|
+
|
|
15
31
|
from tunacode.constants import READ_ONLY_TOOLS
|
|
16
32
|
from tunacode.core.state import StateManager
|
|
17
33
|
from tunacode.services.mcp import get_mcp_servers
|
|
@@ -197,6 +213,7 @@ async def _process_node(
|
|
|
197
213
|
tool_callback: Optional[ToolCallback],
|
|
198
214
|
state_manager: StateManager,
|
|
199
215
|
tool_buffer: Optional[ToolBuffer] = None,
|
|
216
|
+
streaming_callback: Optional[callable] = None,
|
|
200
217
|
):
|
|
201
218
|
from tunacode.ui import console as ui
|
|
202
219
|
from tunacode.utils.token_counter import estimate_tokens
|
|
@@ -216,6 +233,16 @@ async def _process_node(
|
|
|
216
233
|
if hasattr(node, "model_response"):
|
|
217
234
|
state_manager.session.messages.append(node.model_response)
|
|
218
235
|
|
|
236
|
+
# Stream content to callback if provided
|
|
237
|
+
# Use this as fallback when true token streaming is not available
|
|
238
|
+
if streaming_callback and not STREAMING_AVAILABLE:
|
|
239
|
+
for part in node.model_response.parts:
|
|
240
|
+
if hasattr(part, "content") and isinstance(part.content, str):
|
|
241
|
+
content = part.content.strip()
|
|
242
|
+
if content and not content.startswith('{"thought"'):
|
|
243
|
+
# Stream non-JSON content (actual response content)
|
|
244
|
+
await streaming_callback(content)
|
|
245
|
+
|
|
219
246
|
# Enhanced display when thoughts are enabled
|
|
220
247
|
if state_manager.session.show_thoughts:
|
|
221
248
|
# Show raw API response data
|
|
@@ -683,6 +710,7 @@ async def process_request(
|
|
|
683
710
|
message: str,
|
|
684
711
|
state_manager: StateManager,
|
|
685
712
|
tool_callback: Optional[ToolCallback] = None,
|
|
713
|
+
streaming_callback: Optional[callable] = None,
|
|
686
714
|
) -> AgentRun:
|
|
687
715
|
agent = get_or_create_agent(model, state_manager)
|
|
688
716
|
mh = state_manager.session.messages.copy()
|
|
@@ -723,7 +751,19 @@ async def process_request(
|
|
|
723
751
|
i = 0
|
|
724
752
|
async for node in agent_run:
|
|
725
753
|
state_manager.session.current_iteration = i + 1
|
|
726
|
-
|
|
754
|
+
|
|
755
|
+
# Handle token-level streaming for model request nodes
|
|
756
|
+
if streaming_callback and STREAMING_AVAILABLE and Agent.is_model_request_node(node):
|
|
757
|
+
async with node.stream(agent_run.ctx) as request_stream:
|
|
758
|
+
async for event in request_stream:
|
|
759
|
+
if isinstance(event, PartDeltaEvent) and isinstance(
|
|
760
|
+
event.delta, TextPartDelta
|
|
761
|
+
):
|
|
762
|
+
# Stream individual token deltas
|
|
763
|
+
if event.delta.content_delta:
|
|
764
|
+
await streaming_callback(event.delta.content_delta)
|
|
765
|
+
|
|
766
|
+
await _process_node(node, tool_callback, state_manager, tool_buffer, streaming_callback)
|
|
727
767
|
if hasattr(node, "result") and node.result and hasattr(node.result, "output"):
|
|
728
768
|
if node.result.output:
|
|
729
769
|
response_state.has_user_response = True
|