gitarsenal-cli 1.9.18 → 1.9.20
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.
- package/.venv_status.json +1 -1
- package/package.json +1 -1
- package/python/credentials_manager.py +23 -1
- package/python/fetch_modal_tokens.py +47 -22
- package/python/fix_modal_token.py +1 -1
- package/python/modal_auth_patch.py +1 -1
- package/python/modal_proxy_service.py +2 -2
- package/python/modal_token_solution.py +1 -1
- package/python/test_modalSandboxScript.py +675 -8
- package/test_modalSandboxScript.py +675 -8
- package/python/test_claude_fallback.py +0 -118
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-06T11:31:44.083Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/package.json
CHANGED
|
@@ -145,7 +145,7 @@ class CredentialsManager:
|
|
|
145
145
|
# First try to fetch from server using fetch_modal_tokens (GitArsenal's key)
|
|
146
146
|
try:
|
|
147
147
|
from fetch_modal_tokens import get_tokens
|
|
148
|
-
_, _, api_key = get_tokens()
|
|
148
|
+
_, _, api_key, _ = get_tokens()
|
|
149
149
|
if api_key and validate_openai_key(api_key):
|
|
150
150
|
# Set in environment for future use
|
|
151
151
|
os.environ["OPENAI_API_KEY"] = api_key
|
|
@@ -220,6 +220,27 @@ class CredentialsManager:
|
|
|
220
220
|
prompt = "A Weights & Biases API key is required.\nYou can get your API key from: https://wandb.ai/authorize"
|
|
221
221
|
return self.get_credential("wandb_api_key", prompt, is_password=True, validate_func=validate_wandb_key)
|
|
222
222
|
|
|
223
|
+
def get_anthropic_api_key(self):
|
|
224
|
+
"""Get Anthropic API key with validation"""
|
|
225
|
+
def validate_anthropic_key(key):
|
|
226
|
+
# Anthropic keys usually start with "sk-ant-" and are typically 48+ characters
|
|
227
|
+
return key.startswith("sk-ant-") and len(key) > 40
|
|
228
|
+
|
|
229
|
+
# First check stored credentials
|
|
230
|
+
credentials = self.load_credentials()
|
|
231
|
+
if "anthropic_api_key" in credentials:
|
|
232
|
+
stored_key = credentials["anthropic_api_key"]
|
|
233
|
+
if validate_anthropic_key(stored_key):
|
|
234
|
+
return stored_key
|
|
235
|
+
|
|
236
|
+
# Then check environment variable
|
|
237
|
+
env_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
238
|
+
if env_key and validate_anthropic_key(env_key):
|
|
239
|
+
return env_key
|
|
240
|
+
|
|
241
|
+
prompt = "An Anthropic API key is required.\nYou can get your API key from: https://console.anthropic.com/"
|
|
242
|
+
return self.get_credential("anthropic_api_key", prompt, is_password=True, validate_func=validate_anthropic_key)
|
|
243
|
+
|
|
223
244
|
def clear_credential(self, key):
|
|
224
245
|
"""Remove a specific credential"""
|
|
225
246
|
credentials = self.load_credentials()
|
|
@@ -259,6 +280,7 @@ class CredentialsManager:
|
|
|
259
280
|
import os
|
|
260
281
|
security_vars = [
|
|
261
282
|
"OPENAI_API_KEY",
|
|
283
|
+
"ANTHROPIC_API_KEY",
|
|
262
284
|
"HUGGINGFACE_TOKEN",
|
|
263
285
|
"WANDB_API_KEY",
|
|
264
286
|
"MODAL_TOKEN_ID",
|
|
@@ -39,29 +39,30 @@ def fetch_default_tokens_from_gitarsenal():
|
|
|
39
39
|
token_id = data.get("modalTokenId")
|
|
40
40
|
token_secret = data.get("modalTokenSecret")
|
|
41
41
|
openai_api_key = data.get("openaiApiKey")
|
|
42
|
+
anthropic_api_key = data.get("anthropicApiKey")
|
|
42
43
|
|
|
43
44
|
if token_id and token_secret:
|
|
44
45
|
# print("✅ Successfully fetched default tokens from gitarsenal.dev")
|
|
45
|
-
return token_id, token_secret, openai_api_key
|
|
46
|
+
return token_id, token_secret, openai_api_key, anthropic_api_key
|
|
46
47
|
else:
|
|
47
48
|
print("❌ Modal tokens not found in gitarsenal.dev response")
|
|
48
|
-
return None, None, None
|
|
49
|
+
return None, None, None, None
|
|
49
50
|
except json.JSONDecodeError:
|
|
50
51
|
print("❌ Invalid JSON response from gitarsenal.dev")
|
|
51
|
-
return None, None, None
|
|
52
|
+
return None, None, None, None
|
|
52
53
|
else:
|
|
53
54
|
print(f"❌ Failed to fetch from gitarsenal.dev: {response.status_code} - {response.text[:200]}")
|
|
54
|
-
return None, None, None
|
|
55
|
+
return None, None, None, None
|
|
55
56
|
|
|
56
57
|
except requests.exceptions.Timeout:
|
|
57
58
|
print("❌ Request timeout when fetching from gitarsenal.dev")
|
|
58
|
-
return None, None, None
|
|
59
|
+
return None, None, None, None
|
|
59
60
|
except requests.exceptions.ConnectionError:
|
|
60
61
|
print("❌ Connection failed to gitarsenal.dev")
|
|
61
|
-
return None, None, None
|
|
62
|
+
return None, None, None, None
|
|
62
63
|
except requests.exceptions.RequestException as e:
|
|
63
64
|
print(f"❌ Request failed to gitarsenal.dev: {e}")
|
|
64
|
-
return None, None, None
|
|
65
|
+
return None, None, None, None
|
|
65
66
|
|
|
66
67
|
def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
|
|
67
68
|
"""
|
|
@@ -89,12 +90,12 @@ def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
|
|
|
89
90
|
if not proxy_url:
|
|
90
91
|
# print("❌ No proxy URL provided or found in environment")
|
|
91
92
|
print("💡 Set MODAL_PROXY_URL environment variable or use --proxy-url argument")
|
|
92
|
-
return None, None, None
|
|
93
|
+
return None, None, None, None
|
|
93
94
|
|
|
94
95
|
if not api_key:
|
|
95
96
|
print("❌ No API key provided or found in environment")
|
|
96
97
|
print("💡 Set MODAL_PROXY_API_KEY environment variable or use --proxy-api-key argument")
|
|
97
|
-
return None, None, None
|
|
98
|
+
return None, None, None, None
|
|
98
99
|
|
|
99
100
|
# Ensure the URL ends with a slash
|
|
100
101
|
if not proxy_url.endswith("/"):
|
|
@@ -117,41 +118,42 @@ def fetch_tokens_from_proxy(proxy_url=None, api_key=None):
|
|
|
117
118
|
token_id = data.get("token_id")
|
|
118
119
|
token_secret = data.get("token_secret")
|
|
119
120
|
openai_api_key = data.get("openai_api_key")
|
|
121
|
+
anthropic_api_key = data.get("anthropic_api_key")
|
|
120
122
|
|
|
121
123
|
if token_id and token_secret:
|
|
122
124
|
print("✅ Successfully fetched tokens from proxy server")
|
|
123
|
-
return token_id, token_secret, openai_api_key
|
|
125
|
+
return token_id, token_secret, openai_api_key, anthropic_api_key
|
|
124
126
|
else:
|
|
125
127
|
print("❌ Tokens not found in response")
|
|
126
|
-
return None, None, None
|
|
128
|
+
return None, None, None, None
|
|
127
129
|
else:
|
|
128
130
|
print(f"❌ Failed to fetch tokens: {response.status_code} - {response.text}")
|
|
129
|
-
return None, None, None
|
|
131
|
+
return None, None, None, None
|
|
130
132
|
except Exception as e:
|
|
131
133
|
print(f"❌ Error fetching tokens: {e}")
|
|
132
|
-
return None, None, None
|
|
134
|
+
return None, None, None, None
|
|
133
135
|
|
|
134
136
|
def get_tokens():
|
|
135
137
|
"""
|
|
136
|
-
Get Modal tokens and
|
|
138
|
+
Get Modal tokens, OpenAI API key, and Anthropic API key, trying to fetch from the proxy server first.
|
|
137
139
|
Also sets the tokens in environment variables.
|
|
138
140
|
|
|
139
141
|
Returns:
|
|
140
|
-
tuple: (token_id, token_secret, openai_api_key)
|
|
142
|
+
tuple: (token_id, token_secret, openai_api_key, anthropic_api_key)
|
|
141
143
|
"""
|
|
142
144
|
# Try to fetch from the proxy server
|
|
143
|
-
token_id, token_secret, openai_api_key = fetch_tokens_from_proxy()
|
|
145
|
+
token_id, token_secret, openai_api_key, anthropic_api_key = fetch_tokens_from_proxy()
|
|
144
146
|
|
|
145
147
|
# If we couldn't fetch from the server, try to get default tokens from gitarsenal.dev
|
|
146
148
|
if not token_id or not token_secret:
|
|
147
149
|
# print("⚠️ Proxy server failed, trying to fetch default tokens from gitarsenal.dev")
|
|
148
|
-
token_id, token_secret, openai_api_key = fetch_default_tokens_from_gitarsenal()
|
|
150
|
+
token_id, token_secret, openai_api_key, anthropic_api_key = fetch_default_tokens_from_gitarsenal()
|
|
149
151
|
|
|
150
152
|
# If we still don't have tokens, we can't proceed
|
|
151
153
|
if not token_id or not token_secret:
|
|
152
154
|
print("❌ Failed to fetch tokens from both proxy server and gitarsenal.dev")
|
|
153
155
|
print("💡 Please check your network connection and API endpoints")
|
|
154
|
-
return None, None, None
|
|
156
|
+
return None, None, None, None
|
|
155
157
|
|
|
156
158
|
# Debug print the full token values
|
|
157
159
|
# print("\n🔍 DEBUG: FULL TOKEN VALUES:")
|
|
@@ -169,7 +171,11 @@ def get_tokens():
|
|
|
169
171
|
if openai_api_key:
|
|
170
172
|
os.environ["OPENAI_API_KEY"] = openai_api_key
|
|
171
173
|
|
|
172
|
-
|
|
174
|
+
# Set Anthropic API key if available
|
|
175
|
+
if anthropic_api_key:
|
|
176
|
+
os.environ["ANTHROPIC_API_KEY"] = anthropic_api_key
|
|
177
|
+
|
|
178
|
+
return token_id, token_secret, openai_api_key, anthropic_api_key
|
|
173
179
|
|
|
174
180
|
if __name__ == "__main__":
|
|
175
181
|
# Parse command-line arguments if run directly
|
|
@@ -190,22 +196,26 @@ if __name__ == "__main__":
|
|
|
190
196
|
print(f"✅ Set MODAL_PROXY_API_KEY from command line")
|
|
191
197
|
|
|
192
198
|
# Get tokens
|
|
193
|
-
token_id, token_secret, openai_api_key = get_tokens()
|
|
199
|
+
token_id, token_secret, openai_api_key, anthropic_api_key = get_tokens()
|
|
194
200
|
print(f"Token ID: {token_id}")
|
|
195
201
|
print(f"Token Secret: {token_secret}")
|
|
196
202
|
print(f"OpenAI API Key: {openai_api_key[:5] + '...' if openai_api_key else None}")
|
|
203
|
+
print(f"Anthropic API Key: {anthropic_api_key[:5] + '...' if anthropic_api_key else None}")
|
|
197
204
|
|
|
198
205
|
# Check if tokens are set in environment variables
|
|
199
206
|
print(f"\n🔍 DEBUG: Checking environment variables")
|
|
200
207
|
print(f"🔍 MODAL_TOKEN_ID exists: {'Yes' if os.environ.get('MODAL_TOKEN_ID') else 'No'}")
|
|
201
208
|
print(f"🔍 MODAL_TOKEN_SECRET exists: {'Yes' if os.environ.get('MODAL_TOKEN_SECRET') else 'No'}")
|
|
202
209
|
print(f"🔍 OPENAI_API_KEY exists: {'Yes' if os.environ.get('OPENAI_API_KEY') else 'No'}")
|
|
210
|
+
print(f"🔍 ANTHROPIC_API_KEY exists: {'Yes' if os.environ.get('ANTHROPIC_API_KEY') else 'No'}")
|
|
203
211
|
if os.environ.get('MODAL_TOKEN_ID'):
|
|
204
212
|
print(f"🔍 MODAL_TOKEN_ID length: {len(os.environ.get('MODAL_TOKEN_ID'))}")
|
|
205
213
|
if os.environ.get('MODAL_TOKEN_SECRET'):
|
|
206
214
|
print(f"🔍 MODAL_TOKEN_SECRET length: {len(os.environ.get('MODAL_TOKEN_SECRET'))}")
|
|
207
215
|
if os.environ.get('OPENAI_API_KEY'):
|
|
208
216
|
print(f"🔍 OPENAI_API_KEY length: {len(os.environ.get('OPENAI_API_KEY'))}")
|
|
217
|
+
if os.environ.get('ANTHROPIC_API_KEY'):
|
|
218
|
+
print(f"🔍 ANTHROPIC_API_KEY length: {len(os.environ.get('ANTHROPIC_API_KEY'))}")
|
|
209
219
|
|
|
210
220
|
# Write the tokens to a file for use by other scripts
|
|
211
221
|
tokens_file = Path(__file__).parent / "modal_tokens.json"
|
|
@@ -213,7 +223,8 @@ if __name__ == "__main__":
|
|
|
213
223
|
json.dump({
|
|
214
224
|
"token_id": token_id,
|
|
215
225
|
"token_secret": token_secret,
|
|
216
|
-
"openai_api_key": openai_api_key
|
|
226
|
+
"openai_api_key": openai_api_key,
|
|
227
|
+
"anthropic_api_key": anthropic_api_key
|
|
217
228
|
}, f)
|
|
218
229
|
print(f"\n✅ Tokens written to {tokens_file}")
|
|
219
230
|
|
|
@@ -234,7 +245,7 @@ if __name__ == "__main__":
|
|
|
234
245
|
f.write(f"token_secret = {token_secret}\n")
|
|
235
246
|
print(f"✅ Created .modalconfig file at {modalconfig_file}")
|
|
236
247
|
|
|
237
|
-
# Create or update .env file with
|
|
248
|
+
# Create or update .env file with API keys
|
|
238
249
|
env_file = Path.home() / ".env"
|
|
239
250
|
env_content = ""
|
|
240
251
|
if env_file.exists():
|
|
@@ -255,6 +266,20 @@ if __name__ == "__main__":
|
|
|
255
266
|
f.write(env_content)
|
|
256
267
|
print(f"✅ Updated OpenAI API key in {env_file}")
|
|
257
268
|
|
|
269
|
+
# Update or add ANTHROPIC_API_KEY
|
|
270
|
+
if anthropic_api_key:
|
|
271
|
+
if "ANTHROPIC_API_KEY" in env_content:
|
|
272
|
+
# Replace existing key
|
|
273
|
+
import re
|
|
274
|
+
env_content = re.sub(r'ANTHROPIC_API_KEY=.*\n', f'ANTHROPIC_API_KEY={anthropic_api_key}\n', env_content)
|
|
275
|
+
else:
|
|
276
|
+
# Add new key
|
|
277
|
+
env_content += f'\nANTHROPIC_API_KEY={anthropic_api_key}\n'
|
|
278
|
+
|
|
279
|
+
with open(env_file, 'w') as f:
|
|
280
|
+
f.write(env_content)
|
|
281
|
+
print(f"✅ Updated Anthropic API key in {env_file}")
|
|
282
|
+
|
|
258
283
|
# Try to use the Modal CLI to set the token
|
|
259
284
|
try:
|
|
260
285
|
print(f"\n🔄 Setting token via Modal CLI...")
|
|
@@ -42,7 +42,7 @@ except Exception as e:
|
|
|
42
42
|
try:
|
|
43
43
|
# First, try to import the fetch_modal_tokens module
|
|
44
44
|
from fetch_modal_tokens import get_tokens
|
|
45
|
-
TOKEN_ID, TOKEN_SECRET = get_tokens()
|
|
45
|
+
TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
|
|
46
46
|
|
|
47
47
|
# Check if we got valid tokens
|
|
48
48
|
if TOKEN_ID is None or TOKEN_SECRET is None:
|
|
@@ -22,7 +22,7 @@ from pathlib import Path
|
|
|
22
22
|
try:
|
|
23
23
|
# First, try to import the fetch_modal_tokens module
|
|
24
24
|
from fetch_modal_tokens import get_tokens
|
|
25
|
-
TOKEN_ID, TOKEN_SECRET = get_tokens()
|
|
25
|
+
TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
|
|
26
26
|
print(f"✅ Using tokens from proxy server or defaults")
|
|
27
27
|
except ImportError:
|
|
28
28
|
# If the module is not available, use hardcoded tokens
|
|
@@ -118,7 +118,7 @@ def setup_modal_auth():
|
|
|
118
118
|
# Import the fetch_modal_tokens module
|
|
119
119
|
logger.info("Fetching Modal tokens from proxy server...")
|
|
120
120
|
from fetch_modal_tokens import get_tokens
|
|
121
|
-
token_id, token_secret = get_tokens()
|
|
121
|
+
token_id, token_secret, _, _ = get_tokens()
|
|
122
122
|
logger.info("Modal tokens fetched successfully")
|
|
123
123
|
|
|
124
124
|
# Set the tokens in environment variables
|
|
@@ -462,7 +462,7 @@ def create_ssh_container():
|
|
|
462
462
|
# Import the fetch_modal_tokens module
|
|
463
463
|
logger.info("Fetching Modal tokens from proxy server in thread...")
|
|
464
464
|
from fetch_modal_tokens import get_tokens
|
|
465
|
-
token_id, token_secret = get_tokens()
|
|
465
|
+
token_id, token_secret, _, _ = get_tokens()
|
|
466
466
|
logger.info("Modal tokens fetched successfully in thread")
|
|
467
467
|
|
|
468
468
|
# Set the tokens in environment variables
|
|
@@ -25,7 +25,7 @@ import time
|
|
|
25
25
|
try:
|
|
26
26
|
# First, try to import the fetch_modal_tokens module
|
|
27
27
|
from fetch_modal_tokens import get_tokens
|
|
28
|
-
TOKEN_ID, TOKEN_SECRET = get_tokens()
|
|
28
|
+
TOKEN_ID, TOKEN_SECRET, _, _ = get_tokens()
|
|
29
29
|
print(f"✅ Using tokens from proxy server or defaults")
|
|
30
30
|
except ImportError:
|
|
31
31
|
# If the module is not available, use hardcoded tokens
|