tunacode-cli 0.1.21__py3-none-any.whl
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/__init__.py +0 -0
- tunacode/cli/textual_repl.tcss +283 -0
- tunacode/configuration/__init__.py +1 -0
- tunacode/configuration/defaults.py +45 -0
- tunacode/configuration/models.py +147 -0
- tunacode/configuration/models_registry.json +1 -0
- tunacode/configuration/pricing.py +74 -0
- tunacode/configuration/settings.py +35 -0
- tunacode/constants.py +227 -0
- tunacode/core/__init__.py +6 -0
- tunacode/core/agents/__init__.py +39 -0
- tunacode/core/agents/agent_components/__init__.py +48 -0
- tunacode/core/agents/agent_components/agent_config.py +441 -0
- tunacode/core/agents/agent_components/agent_helpers.py +290 -0
- tunacode/core/agents/agent_components/message_handler.py +99 -0
- tunacode/core/agents/agent_components/node_processor.py +477 -0
- tunacode/core/agents/agent_components/response_state.py +129 -0
- tunacode/core/agents/agent_components/result_wrapper.py +51 -0
- tunacode/core/agents/agent_components/state_transition.py +112 -0
- tunacode/core/agents/agent_components/streaming.py +271 -0
- tunacode/core/agents/agent_components/task_completion.py +40 -0
- tunacode/core/agents/agent_components/tool_buffer.py +44 -0
- tunacode/core/agents/agent_components/tool_executor.py +101 -0
- tunacode/core/agents/agent_components/truncation_checker.py +37 -0
- tunacode/core/agents/delegation_tools.py +109 -0
- tunacode/core/agents/main.py +545 -0
- tunacode/core/agents/prompts.py +66 -0
- tunacode/core/agents/research_agent.py +231 -0
- tunacode/core/compaction.py +218 -0
- tunacode/core/prompting/__init__.py +27 -0
- tunacode/core/prompting/loader.py +66 -0
- tunacode/core/prompting/prompting_engine.py +98 -0
- tunacode/core/prompting/sections.py +50 -0
- tunacode/core/prompting/templates.py +69 -0
- tunacode/core/state.py +409 -0
- tunacode/exceptions.py +313 -0
- tunacode/indexing/__init__.py +5 -0
- tunacode/indexing/code_index.py +432 -0
- tunacode/indexing/constants.py +86 -0
- tunacode/lsp/__init__.py +112 -0
- tunacode/lsp/client.py +351 -0
- tunacode/lsp/diagnostics.py +19 -0
- tunacode/lsp/servers.py +101 -0
- tunacode/prompts/default_prompt.md +952 -0
- tunacode/prompts/research/sections/agent_role.xml +5 -0
- tunacode/prompts/research/sections/constraints.xml +14 -0
- tunacode/prompts/research/sections/output_format.xml +57 -0
- tunacode/prompts/research/sections/tool_use.xml +23 -0
- tunacode/prompts/sections/advanced_patterns.xml +255 -0
- tunacode/prompts/sections/agent_role.xml +8 -0
- tunacode/prompts/sections/completion.xml +10 -0
- tunacode/prompts/sections/critical_rules.xml +37 -0
- tunacode/prompts/sections/examples.xml +220 -0
- tunacode/prompts/sections/output_style.xml +94 -0
- tunacode/prompts/sections/parallel_exec.xml +105 -0
- tunacode/prompts/sections/search_pattern.xml +100 -0
- tunacode/prompts/sections/system_info.xml +6 -0
- tunacode/prompts/sections/tool_use.xml +84 -0
- tunacode/prompts/sections/user_instructions.xml +3 -0
- tunacode/py.typed +0 -0
- tunacode/templates/__init__.py +5 -0
- tunacode/templates/loader.py +15 -0
- tunacode/tools/__init__.py +10 -0
- tunacode/tools/authorization/__init__.py +29 -0
- tunacode/tools/authorization/context.py +32 -0
- tunacode/tools/authorization/factory.py +20 -0
- tunacode/tools/authorization/handler.py +58 -0
- tunacode/tools/authorization/notifier.py +35 -0
- tunacode/tools/authorization/policy.py +19 -0
- tunacode/tools/authorization/requests.py +119 -0
- tunacode/tools/authorization/rules.py +72 -0
- tunacode/tools/bash.py +222 -0
- tunacode/tools/decorators.py +213 -0
- tunacode/tools/glob.py +353 -0
- tunacode/tools/grep.py +468 -0
- tunacode/tools/grep_components/__init__.py +9 -0
- tunacode/tools/grep_components/file_filter.py +93 -0
- tunacode/tools/grep_components/pattern_matcher.py +158 -0
- tunacode/tools/grep_components/result_formatter.py +87 -0
- tunacode/tools/grep_components/search_result.py +34 -0
- tunacode/tools/list_dir.py +205 -0
- tunacode/tools/prompts/bash_prompt.xml +10 -0
- tunacode/tools/prompts/glob_prompt.xml +7 -0
- tunacode/tools/prompts/grep_prompt.xml +10 -0
- tunacode/tools/prompts/list_dir_prompt.xml +7 -0
- tunacode/tools/prompts/read_file_prompt.xml +9 -0
- tunacode/tools/prompts/todoclear_prompt.xml +12 -0
- tunacode/tools/prompts/todoread_prompt.xml +16 -0
- tunacode/tools/prompts/todowrite_prompt.xml +28 -0
- tunacode/tools/prompts/update_file_prompt.xml +9 -0
- tunacode/tools/prompts/web_fetch_prompt.xml +11 -0
- tunacode/tools/prompts/write_file_prompt.xml +7 -0
- tunacode/tools/react.py +111 -0
- tunacode/tools/read_file.py +68 -0
- tunacode/tools/todo.py +222 -0
- tunacode/tools/update_file.py +62 -0
- tunacode/tools/utils/__init__.py +1 -0
- tunacode/tools/utils/ripgrep.py +311 -0
- tunacode/tools/utils/text_match.py +352 -0
- tunacode/tools/web_fetch.py +245 -0
- tunacode/tools/write_file.py +34 -0
- tunacode/tools/xml_helper.py +34 -0
- tunacode/types/__init__.py +166 -0
- tunacode/types/base.py +94 -0
- tunacode/types/callbacks.py +53 -0
- tunacode/types/dataclasses.py +121 -0
- tunacode/types/pydantic_ai.py +31 -0
- tunacode/types/state.py +122 -0
- tunacode/ui/__init__.py +6 -0
- tunacode/ui/app.py +542 -0
- tunacode/ui/commands/__init__.py +430 -0
- tunacode/ui/components/__init__.py +1 -0
- tunacode/ui/headless/__init__.py +5 -0
- tunacode/ui/headless/output.py +72 -0
- tunacode/ui/main.py +252 -0
- tunacode/ui/renderers/__init__.py +41 -0
- tunacode/ui/renderers/errors.py +197 -0
- tunacode/ui/renderers/panels.py +550 -0
- tunacode/ui/renderers/search.py +314 -0
- tunacode/ui/renderers/tools/__init__.py +21 -0
- tunacode/ui/renderers/tools/bash.py +247 -0
- tunacode/ui/renderers/tools/diagnostics.py +186 -0
- tunacode/ui/renderers/tools/glob.py +226 -0
- tunacode/ui/renderers/tools/grep.py +228 -0
- tunacode/ui/renderers/tools/list_dir.py +198 -0
- tunacode/ui/renderers/tools/read_file.py +226 -0
- tunacode/ui/renderers/tools/research.py +294 -0
- tunacode/ui/renderers/tools/update_file.py +237 -0
- tunacode/ui/renderers/tools/web_fetch.py +182 -0
- tunacode/ui/repl_support.py +226 -0
- tunacode/ui/screens/__init__.py +16 -0
- tunacode/ui/screens/model_picker.py +303 -0
- tunacode/ui/screens/session_picker.py +181 -0
- tunacode/ui/screens/setup.py +218 -0
- tunacode/ui/screens/theme_picker.py +90 -0
- tunacode/ui/screens/update_confirm.py +69 -0
- tunacode/ui/shell_runner.py +129 -0
- tunacode/ui/styles/layout.tcss +98 -0
- tunacode/ui/styles/modals.tcss +38 -0
- tunacode/ui/styles/panels.tcss +81 -0
- tunacode/ui/styles/theme-nextstep.tcss +303 -0
- tunacode/ui/styles/widgets.tcss +33 -0
- tunacode/ui/styles.py +18 -0
- tunacode/ui/widgets/__init__.py +23 -0
- tunacode/ui/widgets/command_autocomplete.py +62 -0
- tunacode/ui/widgets/editor.py +402 -0
- tunacode/ui/widgets/file_autocomplete.py +47 -0
- tunacode/ui/widgets/messages.py +46 -0
- tunacode/ui/widgets/resource_bar.py +182 -0
- tunacode/ui/widgets/status_bar.py +98 -0
- tunacode/utils/__init__.py +0 -0
- tunacode/utils/config/__init__.py +13 -0
- tunacode/utils/config/user_configuration.py +91 -0
- tunacode/utils/messaging/__init__.py +10 -0
- tunacode/utils/messaging/message_utils.py +34 -0
- tunacode/utils/messaging/token_counter.py +77 -0
- tunacode/utils/parsing/__init__.py +13 -0
- tunacode/utils/parsing/command_parser.py +55 -0
- tunacode/utils/parsing/json_utils.py +188 -0
- tunacode/utils/parsing/retry.py +146 -0
- tunacode/utils/parsing/tool_parser.py +267 -0
- tunacode/utils/security/__init__.py +15 -0
- tunacode/utils/security/command.py +106 -0
- tunacode/utils/system/__init__.py +25 -0
- tunacode/utils/system/gitignore.py +155 -0
- tunacode/utils/system/paths.py +190 -0
- tunacode/utils/ui/__init__.py +9 -0
- tunacode/utils/ui/file_filter.py +135 -0
- tunacode/utils/ui/helpers.py +24 -0
- tunacode_cli-0.1.21.dist-info/METADATA +170 -0
- tunacode_cli-0.1.21.dist-info/RECORD +174 -0
- tunacode_cli-0.1.21.dist-info/WHEEL +4 -0
- tunacode_cli-0.1.21.dist-info/entry_points.txt +2 -0
- tunacode_cli-0.1.21.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Pricing utilities for cost calculation and model pricing lookup."""
|
|
2
|
+
|
|
3
|
+
from tunacode.configuration.models import get_cached_models_registry, parse_model_string
|
|
4
|
+
from tunacode.types import ModelPricing
|
|
5
|
+
|
|
6
|
+
TOKENS_PER_MILLION = 1_000_000
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_model_pricing(model_string: str) -> ModelPricing | None:
|
|
10
|
+
"""Get pricing for a model from cached models_registry data.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
model_string: Full model identifier (e.g., "openrouter:openai/gpt-4.1")
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
ModelPricing with input/output/cached costs per million tokens,
|
|
17
|
+
or None if registry is not loaded, model not found, or has no pricing data.
|
|
18
|
+
"""
|
|
19
|
+
registry = get_cached_models_registry()
|
|
20
|
+
if registry is None:
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
provider_id, model_id = parse_model_string(model_string)
|
|
25
|
+
except ValueError:
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
provider = registry.get(provider_id, {})
|
|
29
|
+
model = provider.get("models", {}).get(model_id, {})
|
|
30
|
+
cost = model.get("cost", {})
|
|
31
|
+
|
|
32
|
+
if not cost:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
return ModelPricing(
|
|
36
|
+
input=cost.get("input", 0.0),
|
|
37
|
+
output=cost.get("output", 0.0),
|
|
38
|
+
cached_input=cost.get("cache_read", 0.0),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def calculate_cost(
|
|
43
|
+
pricing: ModelPricing,
|
|
44
|
+
input_tokens: int,
|
|
45
|
+
cached_tokens: int,
|
|
46
|
+
output_tokens: int,
|
|
47
|
+
) -> float:
|
|
48
|
+
"""Calculate cost in USD from token counts and pricing.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
pricing: ModelPricing with costs per million tokens
|
|
52
|
+
input_tokens: Number of input tokens (non-cached)
|
|
53
|
+
cached_tokens: Number of cached input tokens
|
|
54
|
+
output_tokens: Number of output tokens
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Total cost in USD.
|
|
58
|
+
"""
|
|
59
|
+
input_cost = (input_tokens * pricing.input) / TOKENS_PER_MILLION
|
|
60
|
+
cached_cost = (cached_tokens * pricing.cached_input) / TOKENS_PER_MILLION
|
|
61
|
+
output_cost = (output_tokens * pricing.output) / TOKENS_PER_MILLION
|
|
62
|
+
return input_cost + cached_cost + output_cost
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def format_pricing_display(pricing: ModelPricing) -> str:
|
|
66
|
+
"""Format pricing for display as input/output cost string.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
pricing: ModelPricing with costs per million tokens
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Formatted string (e.g., '$2.00/$8.00' for input/output).
|
|
73
|
+
"""
|
|
74
|
+
return f"${pricing.input:.2f}/${pricing.output:.2f}"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module: tunacode.configuration.settings
|
|
3
|
+
|
|
4
|
+
Application settings management for the TunaCode CLI.
|
|
5
|
+
Handles configuration paths, model registries, and application metadata.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from tunacode.constants import APP_NAME, APP_VERSION, CONFIG_FILE_NAME, ToolName
|
|
11
|
+
from tunacode.types import ConfigFile, ConfigPath
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PathConfig:
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.config_dir: ConfigPath = Path.home() / ".config"
|
|
17
|
+
self.config_file: ConfigFile = self.config_dir / CONFIG_FILE_NAME
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ApplicationSettings:
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.version = APP_VERSION
|
|
23
|
+
self.name = APP_NAME
|
|
24
|
+
self.guide_file = f"{self.name.upper()}.md"
|
|
25
|
+
self.paths = PathConfig()
|
|
26
|
+
self.internal_tools: list[ToolName] = [
|
|
27
|
+
ToolName.BASH,
|
|
28
|
+
ToolName.GLOB,
|
|
29
|
+
ToolName.GREP,
|
|
30
|
+
ToolName.LIST_DIR,
|
|
31
|
+
ToolName.READ_FILE,
|
|
32
|
+
ToolName.RESEARCH_CODEBASE,
|
|
33
|
+
ToolName.UPDATE_FILE,
|
|
34
|
+
ToolName.WRITE_FILE,
|
|
35
|
+
]
|
tunacode/constants.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module: tunacode.constants
|
|
3
|
+
|
|
4
|
+
Global constants and configuration values for the TunaCode CLI application.
|
|
5
|
+
Centralizes all magic strings, UI text, error messages, and application constants.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
KB = 1024
|
|
11
|
+
MB = KB * 1024
|
|
12
|
+
|
|
13
|
+
APP_NAME = "TunaCode"
|
|
14
|
+
APP_VERSION = "0.1.21"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
GUIDE_FILE_NAME = "AGENTS.md"
|
|
18
|
+
ENV_FILE = ".env"
|
|
19
|
+
CONFIG_FILE_NAME = "tunacode.json"
|
|
20
|
+
ENV_OPENAI_BASE_URL = "OPENAI_BASE_URL"
|
|
21
|
+
SETTINGS_BASE_URL = "base_url"
|
|
22
|
+
|
|
23
|
+
MAX_FILE_SIZE = 100 * KB
|
|
24
|
+
MAX_COMMAND_OUTPUT = 5000
|
|
25
|
+
DEFAULT_READ_LIMIT = 2000
|
|
26
|
+
MAX_LINE_LENGTH = 2000
|
|
27
|
+
MAX_FILES_IN_DIR = 50
|
|
28
|
+
MAX_TOTAL_DIR_SIZE = 2 * MB
|
|
29
|
+
DEFAULT_CONTEXT_WINDOW = 200000
|
|
30
|
+
|
|
31
|
+
MAX_CALLBACK_CONTENT = 50_000
|
|
32
|
+
MAX_PANEL_LINES = 30
|
|
33
|
+
MAX_PANEL_LINE_WIDTH = 200
|
|
34
|
+
MAX_SEARCH_RESULTS_DISPLAY = 20
|
|
35
|
+
MODEL_PICKER_UNFILTERED_LIMIT = 50
|
|
36
|
+
|
|
37
|
+
# Tool panel viewport sizing (standardized across all renderers)
|
|
38
|
+
LINES_RESERVED_FOR_HEADER_FOOTER = 4
|
|
39
|
+
TOOL_VIEWPORT_LINES = MAX_PANEL_LINES - LINES_RESERVED_FOR_HEADER_FOOTER
|
|
40
|
+
MIN_VIEWPORT_LINES = 5
|
|
41
|
+
TOOL_PANEL_WIDTH = 80
|
|
42
|
+
URL_DISPLAY_MAX_LENGTH = 70
|
|
43
|
+
|
|
44
|
+
AUTOCOMPLETE_MAX_DEPTH = 3
|
|
45
|
+
AUTOCOMPLETE_RESULT_LIMIT = 50
|
|
46
|
+
|
|
47
|
+
COMMAND_OUTPUT_THRESHOLD = 3500
|
|
48
|
+
COMMAND_OUTPUT_START_INDEX = 2500
|
|
49
|
+
COMMAND_OUTPUT_END_SIZE = 1000
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ToolName(str, Enum):
|
|
53
|
+
"""Enumeration of tool names."""
|
|
54
|
+
|
|
55
|
+
READ_FILE = "read_file"
|
|
56
|
+
WRITE_FILE = "write_file"
|
|
57
|
+
UPDATE_FILE = "update_file"
|
|
58
|
+
BASH = "bash"
|
|
59
|
+
GREP = "grep"
|
|
60
|
+
LIST_DIR = "list_dir"
|
|
61
|
+
GLOB = "glob"
|
|
62
|
+
REACT = "react"
|
|
63
|
+
RESEARCH_CODEBASE = "research_codebase"
|
|
64
|
+
WEB_FETCH = "web_fetch"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
READ_ONLY_TOOLS = [
|
|
68
|
+
ToolName.READ_FILE,
|
|
69
|
+
ToolName.GREP,
|
|
70
|
+
ToolName.LIST_DIR,
|
|
71
|
+
ToolName.GLOB,
|
|
72
|
+
ToolName.REACT,
|
|
73
|
+
ToolName.RESEARCH_CODEBASE,
|
|
74
|
+
ToolName.WEB_FETCH,
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
COMMAND_PREFIX = "/"
|
|
78
|
+
|
|
79
|
+
TUNACODE_HOME_DIR = ".tunacode"
|
|
80
|
+
SESSIONS_SUBDIR = "sessions"
|
|
81
|
+
DEVICE_ID_FILE = "device_id"
|
|
82
|
+
|
|
83
|
+
UI_COLORS = {
|
|
84
|
+
"background": "#1a1a1a",
|
|
85
|
+
"surface": "#252525",
|
|
86
|
+
"border": "#ff6b9d",
|
|
87
|
+
"text": "#e0e0e0",
|
|
88
|
+
"muted": "#808080",
|
|
89
|
+
"primary": "#00d7d7",
|
|
90
|
+
"accent": "#ff6b9d",
|
|
91
|
+
"success": "#4ec9b0",
|
|
92
|
+
"warning": "#c3e88d",
|
|
93
|
+
"error": "#f44747",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
NEXTSTEP_COLORS = {
|
|
97
|
+
"background": "#acacac",
|
|
98
|
+
"surface": "#c8c8c8",
|
|
99
|
+
"window_content": "#d0d0d0",
|
|
100
|
+
"title_bar": "#3a3a3a",
|
|
101
|
+
"title_bar_text": "#e0e0e0",
|
|
102
|
+
"border": "#2a2a2a",
|
|
103
|
+
"text": "#000000",
|
|
104
|
+
"muted": "#404040",
|
|
105
|
+
"bevel_light": "#e8e8e8",
|
|
106
|
+
"bevel_dark": "#606060",
|
|
107
|
+
"primary": "#1a1a1a",
|
|
108
|
+
"accent": "#3a3a3a",
|
|
109
|
+
"success": "#2a2a2a",
|
|
110
|
+
"warning": "#4a4a4a",
|
|
111
|
+
"error": "#1a1a1a",
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
UI_THINKING_MESSAGE = "[bold #00d7ff]Thinking...[/bold #00d7ff]"
|
|
115
|
+
|
|
116
|
+
ERROR_PROVIDER_EMPTY = "Provider number cannot be empty"
|
|
117
|
+
ERROR_INVALID_PROVIDER = "Invalid provider number"
|
|
118
|
+
ERROR_FILE_NOT_FOUND = "Error: File not found at '{filepath}'."
|
|
119
|
+
ERROR_FILE_TOO_LARGE = "Error: File '{filepath}' is too large (> 100KB)."
|
|
120
|
+
ERROR_FILE_DECODE = "Error reading file '{filepath}': Could not decode using UTF-8."
|
|
121
|
+
ERROR_FILE_DECODE_DETAILS = "It might be a binary file or use a different encoding. {error}"
|
|
122
|
+
ERROR_COMMAND_NOT_FOUND = "Error: Command not found or failed to execute:"
|
|
123
|
+
ERROR_COMMAND_EXECUTION = (
|
|
124
|
+
"Error: Command not found or failed to execute: {command}. Details: {error}"
|
|
125
|
+
)
|
|
126
|
+
ERROR_TOOL_CALL_ID_MISSING = "Tool return missing tool_call_id."
|
|
127
|
+
ERROR_TOOL_ARGS_MISSING = "Tool args missing for tool_call_id '{tool_call_id}'."
|
|
128
|
+
|
|
129
|
+
ERROR_DIR_TOO_LARGE = (
|
|
130
|
+
"Error: Directory '{path}' expansion aborted. Total size exceeds {limit_mb:.1f} MB limit."
|
|
131
|
+
)
|
|
132
|
+
ERROR_DIR_TOO_MANY_FILES = (
|
|
133
|
+
"Error: Directory '{path}' expansion aborted. Exceeds limit of {limit} files."
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
CMD_OUTPUT_NO_OUTPUT = "No output."
|
|
137
|
+
CMD_OUTPUT_NO_ERRORS = "No errors."
|
|
138
|
+
CMD_OUTPUT_FORMAT = "STDOUT:\n{output}\n\nSTDERR:\n{error}"
|
|
139
|
+
CMD_OUTPUT_TRUNCATED = "\n...\n[truncated]\n...\n"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
MSG_UPDATE_AVAILABLE = "Update available: v{latest_version}"
|
|
143
|
+
MSG_UPDATE_INSTRUCTION = "Exit, and run: [bold]pip install --upgrade tunacode-cli"
|
|
144
|
+
MSG_VERSION_DISPLAY = "TunaCode CLI {version}"
|
|
145
|
+
MSG_FILE_SIZE_LIMIT = " Please specify a smaller file or use other tools to process it."
|
|
146
|
+
|
|
147
|
+
JSON_PARSE_MAX_RETRIES = 10
|
|
148
|
+
JSON_PARSE_BASE_DELAY = 0.1
|
|
149
|
+
JSON_PARSE_MAX_DELAY = 5.0
|
|
150
|
+
|
|
151
|
+
TOOL_MAX_RETRIES = 3
|
|
152
|
+
TOOL_RETRY_BASE_DELAY = 0.5
|
|
153
|
+
TOOL_RETRY_MAX_DELAY = 5.0
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
THEME_NAME = "tunacode"
|
|
157
|
+
|
|
158
|
+
RESOURCE_BAR_HEIGHT = 1
|
|
159
|
+
RESOURCE_BAR_SEPARATOR = " - "
|
|
160
|
+
RESOURCE_BAR_TOKEN_FORMAT = "{tokens}/{max_tokens}" # nosec B105
|
|
161
|
+
RESOURCE_BAR_COST_FORMAT = "${cost:.2f}"
|
|
162
|
+
RESOURCE_BAR_SESSION_LABEL = "session"
|
|
163
|
+
|
|
164
|
+
RICHLOG_CLASS_PAUSED = "paused"
|
|
165
|
+
RICHLOG_CLASS_STREAMING = "streaming"
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def build_tunacode_theme():
|
|
169
|
+
"""Build and return the TunaCode Textual theme.
|
|
170
|
+
|
|
171
|
+
Uses UI_COLORS palette - high contrast neutral scheme.
|
|
172
|
+
Import Theme lazily to avoid import cycles and allow non-TUI usage.
|
|
173
|
+
"""
|
|
174
|
+
from textual.theme import Theme
|
|
175
|
+
|
|
176
|
+
p = UI_COLORS
|
|
177
|
+
return Theme(
|
|
178
|
+
name=THEME_NAME,
|
|
179
|
+
primary=p["primary"],
|
|
180
|
+
secondary=p["muted"],
|
|
181
|
+
accent=p["accent"],
|
|
182
|
+
background=p["background"],
|
|
183
|
+
surface=p["surface"],
|
|
184
|
+
panel=p["surface"],
|
|
185
|
+
success=p["success"],
|
|
186
|
+
warning=p["warning"],
|
|
187
|
+
error=p["error"],
|
|
188
|
+
foreground=p["text"],
|
|
189
|
+
variables={
|
|
190
|
+
"text-muted": p["muted"],
|
|
191
|
+
"border": p["border"],
|
|
192
|
+
},
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def build_nextstep_theme():
|
|
197
|
+
"""Build and return the NeXTSTEP Textual theme.
|
|
198
|
+
|
|
199
|
+
Classic 1990s NeXTSTEP look - light gray background, black text,
|
|
200
|
+
pure monochrome with no colored accents. High contrast for readability.
|
|
201
|
+
"""
|
|
202
|
+
from textual.theme import Theme
|
|
203
|
+
|
|
204
|
+
p = NEXTSTEP_COLORS
|
|
205
|
+
return Theme(
|
|
206
|
+
name="nextstep",
|
|
207
|
+
dark=False,
|
|
208
|
+
primary=p["primary"],
|
|
209
|
+
secondary=p["muted"],
|
|
210
|
+
accent=p["accent"],
|
|
211
|
+
background=p["background"],
|
|
212
|
+
surface=p["surface"],
|
|
213
|
+
panel=p["surface"],
|
|
214
|
+
success=p["success"],
|
|
215
|
+
warning=p["warning"],
|
|
216
|
+
error=p["error"],
|
|
217
|
+
foreground=p["text"],
|
|
218
|
+
variables={
|
|
219
|
+
"text-muted": p["muted"],
|
|
220
|
+
"border": p["border"],
|
|
221
|
+
"bevel-light": p["bevel_light"],
|
|
222
|
+
"bevel-dark": p["bevel_dark"],
|
|
223
|
+
"title-bar": p["title_bar"],
|
|
224
|
+
"title-bar-text": p["title_bar_text"],
|
|
225
|
+
"window-content": p["window_content"],
|
|
226
|
+
},
|
|
227
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Public entry points for TunaCode agent orchestration."""
|
|
2
|
+
|
|
3
|
+
from . import main as main
|
|
4
|
+
from .agent_components import (
|
|
5
|
+
AgentRunWithState,
|
|
6
|
+
AgentRunWrapper,
|
|
7
|
+
ResponseState,
|
|
8
|
+
SimpleResult,
|
|
9
|
+
ToolBuffer,
|
|
10
|
+
_process_node,
|
|
11
|
+
check_task_completion,
|
|
12
|
+
execute_tools_parallel,
|
|
13
|
+
get_model_messages,
|
|
14
|
+
get_or_create_agent,
|
|
15
|
+
patch_tool_messages,
|
|
16
|
+
)
|
|
17
|
+
from .main import (
|
|
18
|
+
check_query_satisfaction,
|
|
19
|
+
get_agent_tool,
|
|
20
|
+
process_request,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"process_request",
|
|
25
|
+
"get_or_create_agent",
|
|
26
|
+
"get_model_messages",
|
|
27
|
+
"patch_tool_messages",
|
|
28
|
+
"_process_node",
|
|
29
|
+
"ResponseState",
|
|
30
|
+
"SimpleResult",
|
|
31
|
+
"AgentRunWrapper",
|
|
32
|
+
"AgentRunWithState",
|
|
33
|
+
"ToolBuffer",
|
|
34
|
+
"check_task_completion",
|
|
35
|
+
"execute_tools_parallel",
|
|
36
|
+
"check_query_satisfaction",
|
|
37
|
+
"get_agent_tool",
|
|
38
|
+
"main",
|
|
39
|
+
]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Agent components package for modular agent functionality."""
|
|
2
|
+
|
|
3
|
+
from .agent_config import get_or_create_agent
|
|
4
|
+
from .agent_helpers import (
|
|
5
|
+
create_empty_response_message,
|
|
6
|
+
create_fallback_response,
|
|
7
|
+
create_progress_summary,
|
|
8
|
+
create_user_message,
|
|
9
|
+
format_fallback_output,
|
|
10
|
+
get_recent_tools_context,
|
|
11
|
+
get_tool_description,
|
|
12
|
+
get_tool_summary,
|
|
13
|
+
get_user_prompt_part_class,
|
|
14
|
+
handle_empty_response,
|
|
15
|
+
)
|
|
16
|
+
from .message_handler import get_model_messages, patch_tool_messages
|
|
17
|
+
from .node_processor import _process_node
|
|
18
|
+
from .response_state import ResponseState
|
|
19
|
+
from .result_wrapper import AgentRunWithState, AgentRunWrapper, SimpleResult
|
|
20
|
+
from .streaming import stream_model_request_node
|
|
21
|
+
from .task_completion import check_task_completion
|
|
22
|
+
from .tool_buffer import ToolBuffer
|
|
23
|
+
from .tool_executor import execute_tools_parallel
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"get_or_create_agent",
|
|
27
|
+
"get_model_messages",
|
|
28
|
+
"patch_tool_messages",
|
|
29
|
+
"_process_node",
|
|
30
|
+
"ResponseState",
|
|
31
|
+
"AgentRunWithState",
|
|
32
|
+
"AgentRunWrapper",
|
|
33
|
+
"SimpleResult",
|
|
34
|
+
"check_task_completion",
|
|
35
|
+
"ToolBuffer",
|
|
36
|
+
"execute_tools_parallel",
|
|
37
|
+
"create_empty_response_message",
|
|
38
|
+
"create_fallback_response",
|
|
39
|
+
"create_progress_summary",
|
|
40
|
+
"create_user_message",
|
|
41
|
+
"format_fallback_output",
|
|
42
|
+
"get_recent_tools_context",
|
|
43
|
+
"get_tool_description",
|
|
44
|
+
"get_tool_summary",
|
|
45
|
+
"get_user_prompt_part_class",
|
|
46
|
+
"handle_empty_response",
|
|
47
|
+
"stream_model_request_node",
|
|
48
|
+
]
|