tunacode-cli 0.0.7__tar.gz → 0.0.8__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.7 → tunacode_cli-0.0.8}/PKG-INFO +64 -5
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/README.md +62 -3
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/pyproject.toml +2 -2
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/cli/main.py +31 -2
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/constants.py +1 -1
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/agents/tinyagent_main.py +21 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/config_setup.py +61 -53
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/input.py +3 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/prompt_manager.py +2 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/PKG-INFO +64 -5
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/requires.txt +1 -1
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/LICENSE +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/setup.cfg +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/cli/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/cli/commands.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/cli/model_selector.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/cli/repl.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/configuration/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/configuration/defaults.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/configuration/models.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/configuration/settings.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/context.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/agents/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/agents/main.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/agent_setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/base.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/coordinator.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/environment_setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/git_safety_setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/optimized_coordinator.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/setup/undo_setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/state.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/core/tool_handler.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/exceptions.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/prompts/system.txt +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/py.typed +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/services/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/services/enhanced_undo_service.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/services/mcp.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/services/project_undo_service.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/services/undo_service.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/setup.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/base.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/read_file.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/run_command.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/tinyagent_tools.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/update_file.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/tools/write_file.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/types.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/completers.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/console.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/constants.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/decorators.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/keybindings.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/lexers.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/output.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/panels.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/tool_ui.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/ui/validators.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/__init__.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/bm25.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/diff_utils.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/file_utils.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/lazy_imports.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/regex_cache.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/ripgrep.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/system.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/text_utils.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode/utils/user_configuration.py +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/SOURCES.txt +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/dependency_links.txt +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/entry_points.txt +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/src/tunacode_cli.egg-info/top_level.txt +0 -0
- {tunacode_cli-0.0.7 → tunacode_cli-0.0.8}/tests/test_import.py +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.8
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: prompt_toolkit==3.0.51
|
|
|
23
23
|
Requires-Dist: tiny_agent_os>=0.1.0
|
|
24
24
|
Requires-Dist: pygments==2.19.1
|
|
25
25
|
Requires-Dist: rich==14.0.0
|
|
26
|
-
Requires-Dist: typer==0.
|
|
26
|
+
Requires-Dist: typer==0.12.5
|
|
27
27
|
Requires-Dist: pyyaml>=6.0
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: build; extra == "dev"
|
|
@@ -107,6 +107,12 @@ tunacode
|
|
|
107
107
|
|
|
108
108
|
# Update to latest version
|
|
109
109
|
tunacode --update
|
|
110
|
+
|
|
111
|
+
# Start with a specific model
|
|
112
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
113
|
+
|
|
114
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
115
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
110
116
|
```
|
|
111
117
|
|
|
112
118
|
## 📋 Commands
|
|
@@ -144,19 +150,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
144
150
|
}
|
|
145
151
|
```
|
|
146
152
|
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# .env file
|
|
159
|
+
OPENAI_API_KEY=sk-...
|
|
160
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
161
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Environment variables take precedence over config file values.
|
|
165
|
+
|
|
166
|
+
### TinyAgent Configuration
|
|
167
|
+
|
|
168
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# Model and API configuration
|
|
172
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
173
|
+
model:
|
|
174
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
175
|
+
|
|
176
|
+
# File operations
|
|
177
|
+
file_operations:
|
|
178
|
+
max_file_size: 10_485_760 # 10 MB
|
|
179
|
+
allow_overwrite: true
|
|
180
|
+
|
|
181
|
+
# Retry configuration
|
|
182
|
+
retries:
|
|
183
|
+
max_attempts: 3
|
|
184
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
188
|
+
|
|
147
189
|
### Using OpenRouter (100+ Models)
|
|
148
190
|
|
|
149
191
|
```bash
|
|
150
|
-
# Add your OpenRouter API key to config
|
|
151
|
-
#
|
|
152
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
192
|
+
# Add your OpenRouter API key to config or .env file
|
|
193
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
153
194
|
|
|
154
195
|
# Use any OpenRouter model:
|
|
196
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
197
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
198
|
+
|
|
199
|
+
# Or switch models inside TunaCode:
|
|
155
200
|
/model openrouter:anthropic/claude-3-opus
|
|
156
201
|
/model openrouter:mistralai/devstral-small
|
|
157
202
|
/model openrouter:openai/gpt-4.1
|
|
158
203
|
```
|
|
159
204
|
|
|
205
|
+
### OpenAI-Compatible APIs
|
|
206
|
+
|
|
207
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Use a local LLM server
|
|
211
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
212
|
+
|
|
213
|
+
# Use alternative OpenAI-compatible services
|
|
214
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
218
|
+
|
|
160
219
|
## 🛡️ Undo System
|
|
161
220
|
|
|
162
221
|
TunaCode provides **three layers of protection** for your files:
|
|
@@ -71,6 +71,12 @@ tunacode
|
|
|
71
71
|
|
|
72
72
|
# Update to latest version
|
|
73
73
|
tunacode --update
|
|
74
|
+
|
|
75
|
+
# Start with a specific model
|
|
76
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
77
|
+
|
|
78
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
79
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
74
80
|
```
|
|
75
81
|
|
|
76
82
|
## 📋 Commands
|
|
@@ -108,19 +114,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
108
114
|
}
|
|
109
115
|
```
|
|
110
116
|
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
# .env file
|
|
123
|
+
OPENAI_API_KEY=sk-...
|
|
124
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
125
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Environment variables take precedence over config file values.
|
|
129
|
+
|
|
130
|
+
### TinyAgent Configuration
|
|
131
|
+
|
|
132
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# Model and API configuration
|
|
136
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
137
|
+
model:
|
|
138
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
139
|
+
|
|
140
|
+
# File operations
|
|
141
|
+
file_operations:
|
|
142
|
+
max_file_size: 10_485_760 # 10 MB
|
|
143
|
+
allow_overwrite: true
|
|
144
|
+
|
|
145
|
+
# Retry configuration
|
|
146
|
+
retries:
|
|
147
|
+
max_attempts: 3
|
|
148
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
152
|
+
|
|
111
153
|
### Using OpenRouter (100+ Models)
|
|
112
154
|
|
|
113
155
|
```bash
|
|
114
|
-
# Add your OpenRouter API key to config
|
|
115
|
-
#
|
|
116
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
156
|
+
# Add your OpenRouter API key to config or .env file
|
|
157
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
117
158
|
|
|
118
159
|
# Use any OpenRouter model:
|
|
160
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
161
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
162
|
+
|
|
163
|
+
# Or switch models inside TunaCode:
|
|
119
164
|
/model openrouter:anthropic/claude-3-opus
|
|
120
165
|
/model openrouter:mistralai/devstral-small
|
|
121
166
|
/model openrouter:openai/gpt-4.1
|
|
122
167
|
```
|
|
123
168
|
|
|
169
|
+
### OpenAI-Compatible APIs
|
|
170
|
+
|
|
171
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Use a local LLM server
|
|
175
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
176
|
+
|
|
177
|
+
# Use alternative OpenAI-compatible services
|
|
178
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
182
|
+
|
|
124
183
|
## 🛡️ Undo System
|
|
125
184
|
|
|
126
185
|
TunaCode provides **three layers of protection** for your files:
|
|
@@ -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.8"
|
|
8
8
|
description = "Your agentic CLI developer."
|
|
9
9
|
keywords = ["cli", "agent", "development", "automation"]
|
|
10
10
|
readme = "README.md"
|
|
@@ -29,7 +29,7 @@ dependencies = [
|
|
|
29
29
|
"tiny_agent_os>=0.1.0",
|
|
30
30
|
"pygments==2.19.1",
|
|
31
31
|
"rich==14.0.0",
|
|
32
|
-
"typer==0.
|
|
32
|
+
"typer==0.12.5",
|
|
33
33
|
"pyyaml>=6.0",
|
|
34
34
|
]
|
|
35
35
|
|
|
@@ -6,6 +6,8 @@ Manages application startup, version checking, and REPL initialization.
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import asyncio
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
9
11
|
|
|
10
12
|
import typer
|
|
11
13
|
|
|
@@ -17,16 +19,26 @@ from tunacode.ui import console as ui
|
|
|
17
19
|
from tunacode.utils.system import check_for_updates
|
|
18
20
|
|
|
19
21
|
app_settings = ApplicationSettings()
|
|
20
|
-
app = typer.Typer(help=app_settings.name)
|
|
21
22
|
state_manager = StateManager()
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
@app.command()
|
|
25
25
|
def main(
|
|
26
26
|
version: bool = typer.Option(False, "--version", "-v", help="Show version and exit."),
|
|
27
27
|
run_setup: bool = typer.Option(False, "--setup", help="Run setup process."),
|
|
28
28
|
update: bool = typer.Option(False, "--update", "--upgrade", help="Update TunaCode to the latest version."),
|
|
29
|
+
model: str = typer.Option(None, "--model", "-m", help="Set the model to use (e.g., 'openai:gpt-4o', 'openrouter:anthropic/claude-3.5-sonnet')."),
|
|
30
|
+
base_url: str = typer.Option(None, "--base-url", help="Override the API base URL for OpenAI-compatible endpoints (e.g., 'https://openrouter.ai/api/v1')."),
|
|
29
31
|
):
|
|
32
|
+
"""TunaCode - Your agentic CLI developer."""
|
|
33
|
+
# Load .env file if it exists
|
|
34
|
+
env_file = Path(".env")
|
|
35
|
+
if env_file.exists():
|
|
36
|
+
try:
|
|
37
|
+
from dotenv import load_dotenv
|
|
38
|
+
load_dotenv()
|
|
39
|
+
except ImportError:
|
|
40
|
+
# dotenv not installed, skip loading
|
|
41
|
+
pass
|
|
30
42
|
if version:
|
|
31
43
|
asyncio.run(ui.version())
|
|
32
44
|
return
|
|
@@ -36,6 +48,15 @@ def main(
|
|
|
36
48
|
asyncio.run(update_tunacode())
|
|
37
49
|
return
|
|
38
50
|
|
|
51
|
+
# Apply CLI overrides to state manager before setup
|
|
52
|
+
if model:
|
|
53
|
+
state_manager.session.model = model
|
|
54
|
+
state_manager.session.user_config["default_model"] = model
|
|
55
|
+
|
|
56
|
+
if base_url:
|
|
57
|
+
import os
|
|
58
|
+
os.environ["OPENAI_BASE_URL"] = base_url
|
|
59
|
+
|
|
39
60
|
asyncio.run(ui.banner())
|
|
40
61
|
|
|
41
62
|
has_update, latest_version = check_for_updates()
|
|
@@ -49,5 +70,13 @@ def main(
|
|
|
49
70
|
asyncio.run(ui.error(str(e)))
|
|
50
71
|
|
|
51
72
|
|
|
73
|
+
app = typer.Typer(
|
|
74
|
+
name="tunacode",
|
|
75
|
+
help="TunaCode - Your agentic CLI developer",
|
|
76
|
+
add_completion=False,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
app.command()(main)
|
|
80
|
+
|
|
52
81
|
if __name__ == "__main__":
|
|
53
82
|
app()
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""TinyAgent-based agent implementation."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from contextlib import asynccontextmanager
|
|
4
5
|
from datetime import datetime, timezone
|
|
6
|
+
from pathlib import Path
|
|
5
7
|
from typing import Any, Dict, Optional
|
|
6
8
|
|
|
7
9
|
from tinyagent import ReactAgent
|
|
@@ -10,6 +12,25 @@ from tunacode.core.state import StateManager
|
|
|
10
12
|
from tunacode.tools.tinyagent_tools import read_file, run_command, update_file, write_file
|
|
11
13
|
from tunacode.types import ModelName, ToolCallback
|
|
12
14
|
|
|
15
|
+
# Set up tinyagent configuration
|
|
16
|
+
# First check if config exists in the package directory
|
|
17
|
+
_package_dir = Path(__file__).parent.parent.parent.parent # Navigate to tunacode root
|
|
18
|
+
_config_candidates = [
|
|
19
|
+
_package_dir / "tunacode_config.yml", # In package root
|
|
20
|
+
Path.home() / ".config" / "tunacode_config.yml", # In user config dir
|
|
21
|
+
Path.cwd() / "tunacode_config.yml", # In current directory
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
# Find the first existing config file
|
|
25
|
+
for config_path in _config_candidates:
|
|
26
|
+
if config_path.exists():
|
|
27
|
+
os.environ["TINYAGENT_CONFIG"] = str(config_path)
|
|
28
|
+
break
|
|
29
|
+
else:
|
|
30
|
+
# If no config found, we'll rely on tinyagent to handle it
|
|
31
|
+
# This prevents the immediate error on import
|
|
32
|
+
pass
|
|
33
|
+
|
|
13
34
|
|
|
14
35
|
def get_or_create_react_agent(model: ModelName, state_manager: StateManager) -> ReactAgent:
|
|
15
36
|
"""
|
|
@@ -65,14 +65,14 @@ class ConfigSetup(BaseSetup):
|
|
|
65
65
|
# Check if the configured model still exists
|
|
66
66
|
default_model = self.state_manager.session.user_config["default_model"]
|
|
67
67
|
if not self.model_registry.get_model(default_model):
|
|
68
|
+
# If model not found, run the onboarding again
|
|
68
69
|
await ui.panel(
|
|
69
70
|
"Model Not Found",
|
|
70
71
|
f"The configured model '[bold]{default_model}[/bold]' is no longer available.\n"
|
|
71
|
-
"
|
|
72
|
+
"Let's reconfigure your setup.",
|
|
72
73
|
border_style=UI_COLORS["warning"],
|
|
73
74
|
)
|
|
74
|
-
await self.
|
|
75
|
-
user_configuration.save_config(self.state_manager)
|
|
75
|
+
await self._onboarding()
|
|
76
76
|
|
|
77
77
|
self.state_manager.session.current_model = self.state_manager.session.user_config[
|
|
78
78
|
"default_model"
|
|
@@ -114,66 +114,74 @@ class ConfigSetup(BaseSetup):
|
|
|
114
114
|
"""Run the onboarding process for new users."""
|
|
115
115
|
initial_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
# Welcome message
|
|
118
|
+
message = (
|
|
119
|
+
f"Welcome to {APP_NAME}!\n\n"
|
|
120
|
+
"Let's configure your AI provider. TunaCode supports:\n"
|
|
121
|
+
"• OpenAI (api.openai.com)\n"
|
|
122
|
+
"• OpenRouter (openrouter.ai) - Access 100+ models\n"
|
|
123
|
+
"• Any OpenAI-compatible API\n"
|
|
124
|
+
)
|
|
125
|
+
await ui.panel("Setup", message, border_style=UI_COLORS["primary"])
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
# Step 1: Ask for base URL
|
|
128
|
+
base_url = await ui.input(
|
|
129
|
+
"step1",
|
|
130
|
+
pretext=" API Base URL (press Enter for OpenAI): ",
|
|
131
|
+
default="https://api.openai.com/v1",
|
|
132
|
+
state_manager=self.state_manager,
|
|
133
|
+
)
|
|
134
|
+
base_url = base_url.strip()
|
|
135
|
+
if not base_url:
|
|
136
|
+
base_url = "https://api.openai.com/v1"
|
|
137
|
+
|
|
138
|
+
# Step 2: Ask for API key
|
|
139
|
+
if "openrouter.ai" in base_url.lower():
|
|
140
|
+
key_prompt = " OpenRouter API Key: "
|
|
141
|
+
key_name = "OPENROUTER_API_KEY"
|
|
142
|
+
default_model = "openrouter:openai/gpt-4o-mini"
|
|
143
|
+
else:
|
|
144
|
+
key_prompt = " API Key: "
|
|
145
|
+
key_name = "OPENAI_API_KEY"
|
|
146
|
+
default_model = "openai:gpt-4o"
|
|
126
147
|
|
|
127
|
-
|
|
148
|
+
api_key = await ui.input(
|
|
149
|
+
"step2",
|
|
150
|
+
pretext=key_prompt,
|
|
151
|
+
is_password=True,
|
|
152
|
+
state_manager=self.state_manager,
|
|
153
|
+
)
|
|
154
|
+
api_key = api_key.strip()
|
|
155
|
+
|
|
156
|
+
if api_key:
|
|
157
|
+
# Set the environment variable
|
|
158
|
+
self.state_manager.session.user_config["env"][key_name] = api_key
|
|
159
|
+
|
|
160
|
+
# Set base URL in environment for OpenRouter
|
|
161
|
+
if "openrouter.ai" in base_url.lower():
|
|
162
|
+
import os
|
|
163
|
+
os.environ["OPENAI_BASE_URL"] = base_url
|
|
164
|
+
|
|
165
|
+
# Set default model
|
|
166
|
+
self.state_manager.session.user_config["default_model"] = default_model
|
|
167
|
+
|
|
168
|
+
# Save configuration
|
|
128
169
|
current_config = json.dumps(self.state_manager.session.user_config, sort_keys=True)
|
|
129
170
|
if initial_config != current_config:
|
|
130
171
|
if user_configuration.save_config(self.state_manager):
|
|
131
|
-
message =
|
|
132
|
-
|
|
172
|
+
message = (
|
|
173
|
+
f"✅ Configuration saved!\n\n"
|
|
174
|
+
f"Default model: {default_model}\n"
|
|
175
|
+
f"Config file: {self.config_file}\n\n"
|
|
176
|
+
f"You can change models anytime with /model"
|
|
177
|
+
)
|
|
178
|
+
await ui.panel("Setup Complete", message, top=0, border_style=UI_COLORS["success"])
|
|
133
179
|
else:
|
|
134
180
|
await ui.error("Failed to save configuration.")
|
|
135
181
|
else:
|
|
136
182
|
await ui.panel(
|
|
137
183
|
"Setup canceled",
|
|
138
|
-
"
|
|
184
|
+
"An API key is required to use TunaCode.",
|
|
139
185
|
border_style=UI_COLORS["warning"],
|
|
140
186
|
)
|
|
141
187
|
|
|
142
|
-
async def _step1_api_keys(self):
|
|
143
|
-
"""Onboarding step 1: Collect API keys."""
|
|
144
|
-
message = (
|
|
145
|
-
f"Welcome to {APP_NAME}!\n"
|
|
146
|
-
"Let's get you setup. First, we'll need to set some environment variables.\n"
|
|
147
|
-
"Skip the ones you don't need."
|
|
148
|
-
)
|
|
149
|
-
await ui.panel("Setup", message, border_style=UI_COLORS["primary"])
|
|
150
|
-
env_keys = self.state_manager.session.user_config["env"].copy()
|
|
151
|
-
for key in env_keys:
|
|
152
|
-
provider = key_to_title(key)
|
|
153
|
-
val = await ui.input(
|
|
154
|
-
"step1",
|
|
155
|
-
pretext=f" {provider}: ",
|
|
156
|
-
is_password=True,
|
|
157
|
-
state_manager=self.state_manager,
|
|
158
|
-
)
|
|
159
|
-
val = val.strip()
|
|
160
|
-
if val:
|
|
161
|
-
self.state_manager.session.user_config["env"][key] = val
|
|
162
|
-
|
|
163
|
-
async def _step2_default_model(self):
|
|
164
|
-
"""Onboarding step 2: Select default model."""
|
|
165
|
-
message = "Which model would you like to use by default?\n\n"
|
|
166
|
-
|
|
167
|
-
model_ids = self.model_registry.list_model_ids()
|
|
168
|
-
for index, model_id in enumerate(model_ids):
|
|
169
|
-
message += f" {index} - {model_id}\n"
|
|
170
|
-
message = message.strip()
|
|
171
|
-
|
|
172
|
-
await ui.panel("Default Model", message, border_style=UI_COLORS["primary"])
|
|
173
|
-
choice = await ui.input(
|
|
174
|
-
"step2",
|
|
175
|
-
pretext=" Default model (#): ",
|
|
176
|
-
validator=ui.ModelValidator(len(model_ids)),
|
|
177
|
-
state_manager=self.state_manager,
|
|
178
|
-
)
|
|
179
|
-
self.state_manager.session.user_config["default_model"] = model_ids[int(choice)]
|
|
@@ -32,6 +32,7 @@ async def input(
|
|
|
32
32
|
lexer=None,
|
|
33
33
|
timeoutlen: float = 0.05,
|
|
34
34
|
state_manager: Optional[StateManager] = None,
|
|
35
|
+
default: str = "",
|
|
35
36
|
) -> str:
|
|
36
37
|
"""
|
|
37
38
|
Prompt for user input using simplified prompt management.
|
|
@@ -48,6 +49,7 @@ async def input(
|
|
|
48
49
|
lexer: Optional lexer for syntax highlighting
|
|
49
50
|
timeoutlen: Timeout length for input
|
|
50
51
|
state_manager: The state manager for session storage
|
|
52
|
+
default: Default value to pre-fill in the input
|
|
51
53
|
|
|
52
54
|
Returns:
|
|
53
55
|
User input string
|
|
@@ -62,6 +64,7 @@ async def input(
|
|
|
62
64
|
completer=completer,
|
|
63
65
|
lexer=lexer,
|
|
64
66
|
timeoutlen=timeoutlen,
|
|
67
|
+
default=default,
|
|
65
68
|
)
|
|
66
69
|
|
|
67
70
|
# Create prompt manager
|
|
@@ -28,6 +28,7 @@ class PromptConfig:
|
|
|
28
28
|
completer: Optional[Completer] = None
|
|
29
29
|
lexer: Optional[Lexer] = None
|
|
30
30
|
timeoutlen: float = 0.05
|
|
31
|
+
default: str = ""
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class PromptManager:
|
|
@@ -107,6 +108,7 @@ class PromptManager:
|
|
|
107
108
|
is_password=config.is_password,
|
|
108
109
|
validator=config.validator,
|
|
109
110
|
multiline=config.multiline,
|
|
111
|
+
default=config.default,
|
|
110
112
|
)
|
|
111
113
|
|
|
112
114
|
# Clean up response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunacode-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
4
4
|
Summary: Your agentic CLI developer.
|
|
5
5
|
Author-email: larock22 <noreply@github.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,7 +23,7 @@ Requires-Dist: prompt_toolkit==3.0.51
|
|
|
23
23
|
Requires-Dist: tiny_agent_os>=0.1.0
|
|
24
24
|
Requires-Dist: pygments==2.19.1
|
|
25
25
|
Requires-Dist: rich==14.0.0
|
|
26
|
-
Requires-Dist: typer==0.
|
|
26
|
+
Requires-Dist: typer==0.12.5
|
|
27
27
|
Requires-Dist: pyyaml>=6.0
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: build; extra == "dev"
|
|
@@ -107,6 +107,12 @@ tunacode
|
|
|
107
107
|
|
|
108
108
|
# Update to latest version
|
|
109
109
|
tunacode --update
|
|
110
|
+
|
|
111
|
+
# Start with a specific model
|
|
112
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
113
|
+
|
|
114
|
+
# Use a custom OpenAI-compatible API endpoint
|
|
115
|
+
tunacode --base-url https://your-api.com/v1 --model custom:gpt-4
|
|
110
116
|
```
|
|
111
117
|
|
|
112
118
|
## 📋 Commands
|
|
@@ -144,19 +150,72 @@ Configuration is stored in `~/.config/tunacode.json`:
|
|
|
144
150
|
}
|
|
145
151
|
```
|
|
146
152
|
|
|
153
|
+
### Environment Variables
|
|
154
|
+
|
|
155
|
+
TunaCode automatically loads environment variables from a `.env` file in your current directory:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# .env file
|
|
159
|
+
OPENAI_API_KEY=sk-...
|
|
160
|
+
OPENROUTER_API_KEY=sk-or-v1-...
|
|
161
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Environment variables take precedence over config file values.
|
|
165
|
+
|
|
166
|
+
### TinyAgent Configuration
|
|
167
|
+
|
|
168
|
+
TunaCode uses [TinyAgent](https://github.com/alchemiststudiosDOTai/tiny_agent_os) under the hood. Advanced configuration is stored in `~/.config/tunacode_config.yml`:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
# Model and API configuration
|
|
172
|
+
base_url: ${OPENAI_BASE_URL:-https://api.openai.com/v1}
|
|
173
|
+
model:
|
|
174
|
+
default: "gpt-4o" # Overridden by TunaCode's model selection
|
|
175
|
+
|
|
176
|
+
# File operations
|
|
177
|
+
file_operations:
|
|
178
|
+
max_file_size: 10_485_760 # 10 MB
|
|
179
|
+
allow_overwrite: true
|
|
180
|
+
|
|
181
|
+
# Retry configuration
|
|
182
|
+
retries:
|
|
183
|
+
max_attempts: 3
|
|
184
|
+
temperature: { initial: 0.2, increment: 0.3, max: 0.8 }
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This file is automatically created during installation. Most users won't need to modify it.
|
|
188
|
+
|
|
147
189
|
### Using OpenRouter (100+ Models)
|
|
148
190
|
|
|
149
191
|
```bash
|
|
150
|
-
# Add your OpenRouter API key to config
|
|
151
|
-
#
|
|
152
|
-
OPENAI_BASE_URL="https://openrouter.ai/api/v1" tunacode
|
|
192
|
+
# Add your OpenRouter API key to config or .env file
|
|
193
|
+
# TunaCode automatically sets the correct base URL for OpenRouter models
|
|
153
194
|
|
|
154
195
|
# Use any OpenRouter model:
|
|
196
|
+
tunacode --model openrouter:openai/gpt-4o-mini
|
|
197
|
+
tunacode --model openrouter:anthropic/claude-3.5-sonnet
|
|
198
|
+
|
|
199
|
+
# Or switch models inside TunaCode:
|
|
155
200
|
/model openrouter:anthropic/claude-3-opus
|
|
156
201
|
/model openrouter:mistralai/devstral-small
|
|
157
202
|
/model openrouter:openai/gpt-4.1
|
|
158
203
|
```
|
|
159
204
|
|
|
205
|
+
### OpenAI-Compatible APIs
|
|
206
|
+
|
|
207
|
+
TunaCode supports any OpenAI-compatible API endpoint. The `--base-url` flag overrides the API endpoint for providers that use the OpenAI API format:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Use a local LLM server
|
|
211
|
+
tunacode --base-url http://localhost:8080/v1 --model local:llama2
|
|
212
|
+
|
|
213
|
+
# Use alternative OpenAI-compatible services
|
|
214
|
+
tunacode --base-url https://api.together.ai/v1 --model together:llama-2-70b
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Note**: The base URL override only works with OpenAI-compatible APIs that follow the same request/response format as OpenAI's API.
|
|
218
|
+
|
|
160
219
|
## 🛡️ Undo System
|
|
161
220
|
|
|
162
221
|
TunaCode provides **three layers of protection** for your files:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|