daita-agents 0.2.0__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.
- daita/__init__.py +216 -0
- daita/agents/__init__.py +33 -0
- daita/agents/base.py +743 -0
- daita/agents/substrate.py +1141 -0
- daita/cli/__init__.py +145 -0
- daita/cli/__main__.py +7 -0
- daita/cli/ascii_art.py +44 -0
- daita/cli/core/__init__.py +0 -0
- daita/cli/core/create.py +254 -0
- daita/cli/core/deploy.py +473 -0
- daita/cli/core/deployments.py +309 -0
- daita/cli/core/import_detector.py +219 -0
- daita/cli/core/init.py +481 -0
- daita/cli/core/logs.py +239 -0
- daita/cli/core/managed_deploy.py +709 -0
- daita/cli/core/run.py +648 -0
- daita/cli/core/status.py +421 -0
- daita/cli/core/test.py +239 -0
- daita/cli/core/webhooks.py +172 -0
- daita/cli/main.py +588 -0
- daita/cli/utils.py +541 -0
- daita/config/__init__.py +62 -0
- daita/config/base.py +159 -0
- daita/config/settings.py +184 -0
- daita/core/__init__.py +262 -0
- daita/core/decision_tracing.py +701 -0
- daita/core/exceptions.py +480 -0
- daita/core/focus.py +251 -0
- daita/core/interfaces.py +76 -0
- daita/core/plugin_tracing.py +550 -0
- daita/core/relay.py +779 -0
- daita/core/reliability.py +381 -0
- daita/core/scaling.py +459 -0
- daita/core/tools.py +554 -0
- daita/core/tracing.py +770 -0
- daita/core/workflow.py +1144 -0
- daita/display/__init__.py +1 -0
- daita/display/console.py +160 -0
- daita/execution/__init__.py +58 -0
- daita/execution/client.py +856 -0
- daita/execution/exceptions.py +92 -0
- daita/execution/models.py +317 -0
- daita/llm/__init__.py +60 -0
- daita/llm/anthropic.py +291 -0
- daita/llm/base.py +530 -0
- daita/llm/factory.py +101 -0
- daita/llm/gemini.py +355 -0
- daita/llm/grok.py +219 -0
- daita/llm/mock.py +172 -0
- daita/llm/openai.py +220 -0
- daita/plugins/__init__.py +141 -0
- daita/plugins/base.py +37 -0
- daita/plugins/base_db.py +167 -0
- daita/plugins/elasticsearch.py +849 -0
- daita/plugins/mcp.py +481 -0
- daita/plugins/mongodb.py +520 -0
- daita/plugins/mysql.py +362 -0
- daita/plugins/postgresql.py +342 -0
- daita/plugins/redis_messaging.py +500 -0
- daita/plugins/rest.py +537 -0
- daita/plugins/s3.py +770 -0
- daita/plugins/slack.py +729 -0
- daita/utils/__init__.py +18 -0
- daita_agents-0.2.0.dist-info/METADATA +409 -0
- daita_agents-0.2.0.dist-info/RECORD +69 -0
- daita_agents-0.2.0.dist-info/WHEEL +5 -0
- daita_agents-0.2.0.dist-info/entry_points.txt +2 -0
- daita_agents-0.2.0.dist-info/licenses/LICENSE +56 -0
- daita_agents-0.2.0.dist-info/top_level.txt +1 -0
daita/cli/core/logs.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple logs display for Daita CLI.
|
|
3
|
+
Shows deployment history and logs like git log from cloud API.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
import aiohttp
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from ..utils import find_project_root
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def show_deployment_logs(environment=None, limit=10, follow=False, verbose=False):
|
|
12
|
+
"""Show deployment logs (like git log) from cloud API."""
|
|
13
|
+
|
|
14
|
+
# Check API key first
|
|
15
|
+
api_key = os.getenv('DAITA_API_KEY')
|
|
16
|
+
if not api_key:
|
|
17
|
+
from ..utils import show_upgrade_message
|
|
18
|
+
show_upgrade_message()
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
# Get current project name for display
|
|
22
|
+
project_root = find_project_root()
|
|
23
|
+
current_project = None
|
|
24
|
+
if project_root:
|
|
25
|
+
import yaml
|
|
26
|
+
config_file = project_root / 'daita-project.yaml'
|
|
27
|
+
if config_file.exists():
|
|
28
|
+
try:
|
|
29
|
+
with open(config_file, 'r') as f:
|
|
30
|
+
config = yaml.safe_load(f)
|
|
31
|
+
current_project = config.get('name')
|
|
32
|
+
except:
|
|
33
|
+
current_project = None
|
|
34
|
+
|
|
35
|
+
# Load deployments from cloud API
|
|
36
|
+
deployments, api_error = await _load_cloud_deployments(environment, limit)
|
|
37
|
+
|
|
38
|
+
if api_error:
|
|
39
|
+
print(f" Failed to fetch deployments: {api_error}")
|
|
40
|
+
if verbose:
|
|
41
|
+
print(f" API Key: {api_key[:20]}...")
|
|
42
|
+
print(f" Endpoint: {os.getenv('DAITA_API_ENDPOINT', 'https://api.daita.ai')}")
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
if not deployments:
|
|
46
|
+
if current_project:
|
|
47
|
+
if environment:
|
|
48
|
+
print(f" No deployments found ({current_project}, {environment})")
|
|
49
|
+
else:
|
|
50
|
+
print(f" No deployments found ({current_project})")
|
|
51
|
+
print(" Run 'daita push staging' to create your first deployment")
|
|
52
|
+
else:
|
|
53
|
+
print(" No deployments found")
|
|
54
|
+
if environment:
|
|
55
|
+
print(f" No deployments found for environment: {environment}")
|
|
56
|
+
else:
|
|
57
|
+
print(" Run 'daita push staging' to create your first deployment")
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
# Filter by environment if specified (additional client-side filtering)
|
|
61
|
+
if environment:
|
|
62
|
+
deployments = [d for d in deployments if d['environment'] == environment]
|
|
63
|
+
if not deployments:
|
|
64
|
+
print(f" No deployments found for environment: {environment}")
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
# Take most recent deployments (API already returns newest first)
|
|
68
|
+
deployments = deployments[:limit]
|
|
69
|
+
|
|
70
|
+
# Find the most recent active deployment
|
|
71
|
+
latest_active_deployment = None
|
|
72
|
+
for deployment in deployments:
|
|
73
|
+
if deployment.get('status') == 'active':
|
|
74
|
+
latest_active_deployment = deployment
|
|
75
|
+
break
|
|
76
|
+
|
|
77
|
+
# Build header with scope indication
|
|
78
|
+
header_parts = []
|
|
79
|
+
if current_project:
|
|
80
|
+
header_parts.append(current_project)
|
|
81
|
+
if environment:
|
|
82
|
+
header_parts.append(environment)
|
|
83
|
+
|
|
84
|
+
if header_parts:
|
|
85
|
+
scope_info = f" ({', '.join(header_parts)})"
|
|
86
|
+
elif current_project is None:
|
|
87
|
+
scope_info = " (Organization)"
|
|
88
|
+
else:
|
|
89
|
+
scope_info = ""
|
|
90
|
+
|
|
91
|
+
print(f" Deployment History{scope_info}")
|
|
92
|
+
print("")
|
|
93
|
+
|
|
94
|
+
for i, deployment in enumerate(deployments):
|
|
95
|
+
is_current = (latest_active_deployment and
|
|
96
|
+
deployment.get('deployment_id') == latest_active_deployment.get('deployment_id'))
|
|
97
|
+
_show_deployment(deployment, verbose, is_latest=is_current)
|
|
98
|
+
if i < len(deployments) - 1:
|
|
99
|
+
print("")
|
|
100
|
+
|
|
101
|
+
if follow:
|
|
102
|
+
print(f"\n Following logs... (Press Ctrl+C to stop)")
|
|
103
|
+
try:
|
|
104
|
+
import asyncio
|
|
105
|
+
while True:
|
|
106
|
+
await asyncio.sleep(5)
|
|
107
|
+
# Check for new deployments
|
|
108
|
+
new_deployments, error = await _load_cloud_deployments(environment, limit)
|
|
109
|
+
if error:
|
|
110
|
+
continue # Skip this check if API fails
|
|
111
|
+
|
|
112
|
+
if len(new_deployments) > len(deployments):
|
|
113
|
+
latest = new_deployments[-1]
|
|
114
|
+
print(f"\n New deployment:")
|
|
115
|
+
_show_deployment(latest, verbose, is_latest=True)
|
|
116
|
+
deployments = new_deployments
|
|
117
|
+
except KeyboardInterrupt:
|
|
118
|
+
print(f"\n Stopped following logs")
|
|
119
|
+
|
|
120
|
+
def _show_deployment(deployment, verbose, is_latest=False):
|
|
121
|
+
"""Show a single deployment entry."""
|
|
122
|
+
env = deployment['environment']
|
|
123
|
+
timestamp = deployment['deployed_at']
|
|
124
|
+
version = deployment.get('version', '1.0.0')
|
|
125
|
+
project = deployment.get('project_name', 'Unknown')
|
|
126
|
+
|
|
127
|
+
# Format timestamp
|
|
128
|
+
if timestamp:
|
|
129
|
+
# Handle ISO format from API
|
|
130
|
+
if 'T' in timestamp:
|
|
131
|
+
dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
|
|
132
|
+
time_str = dt.strftime('%Y-%m-%d %H:%M:%S')
|
|
133
|
+
else:
|
|
134
|
+
time_str = timestamp
|
|
135
|
+
else:
|
|
136
|
+
time_str = 'Unknown time'
|
|
137
|
+
|
|
138
|
+
# Status indicator
|
|
139
|
+
status = "●" if is_latest else "○"
|
|
140
|
+
current = " (current)" if is_latest else ""
|
|
141
|
+
|
|
142
|
+
print(f"{status} {env}: {project} v{version}{current}")
|
|
143
|
+
print(f" {time_str}")
|
|
144
|
+
|
|
145
|
+
if verbose:
|
|
146
|
+
# Show detailed info
|
|
147
|
+
agents = deployment.get('agents_config', [])
|
|
148
|
+
workflows = deployment.get('workflows_config', [])
|
|
149
|
+
|
|
150
|
+
if agents:
|
|
151
|
+
agent_names = [agent.get('name', 'unknown') for agent in agents]
|
|
152
|
+
print(f" Agents: {', '.join(agent_names)}")
|
|
153
|
+
if workflows:
|
|
154
|
+
workflow_names = [wf.get('name', 'unknown') for wf in workflows]
|
|
155
|
+
print(f" Workflows: {', '.join(workflow_names)}")
|
|
156
|
+
|
|
157
|
+
# Show deployment ID
|
|
158
|
+
deploy_id = deployment.get('deployment_id', 'N/A')
|
|
159
|
+
if len(deploy_id) > 8:
|
|
160
|
+
deploy_id = deploy_id[:8] # Show first 8 characters
|
|
161
|
+
print(f" ID: {deploy_id}")
|
|
162
|
+
|
|
163
|
+
# Show status
|
|
164
|
+
status = deployment.get('status', 'unknown')
|
|
165
|
+
print(f" Status: {status}")
|
|
166
|
+
|
|
167
|
+
async def _load_cloud_deployments(environment=None, limit=10):
|
|
168
|
+
"""Load deployment history from cloud API."""
|
|
169
|
+
try:
|
|
170
|
+
api_key = os.getenv('DAITA_API_KEY')
|
|
171
|
+
if not api_key:
|
|
172
|
+
return [], "API key not found"
|
|
173
|
+
|
|
174
|
+
# Get current project name to filter deployments when in project directory
|
|
175
|
+
project_root = find_project_root()
|
|
176
|
+
if project_root:
|
|
177
|
+
import yaml
|
|
178
|
+
config_file = project_root / 'daita-project.yaml'
|
|
179
|
+
current_project = None
|
|
180
|
+
if config_file.exists():
|
|
181
|
+
try:
|
|
182
|
+
with open(config_file, 'r') as f:
|
|
183
|
+
config = yaml.safe_load(f)
|
|
184
|
+
current_project = config.get('name')
|
|
185
|
+
except:
|
|
186
|
+
current_project = None
|
|
187
|
+
else:
|
|
188
|
+
current_project = None
|
|
189
|
+
|
|
190
|
+
api_endpoint = os.getenv('DAITA_API_ENDPOINT', 'https://ondk4sdyv0.execute-api.us-east-1.amazonaws.com')
|
|
191
|
+
|
|
192
|
+
headers = {
|
|
193
|
+
"Authorization": f"Bearer {api_key}",
|
|
194
|
+
"User-Agent": "Daita-CLI/1.0.0"
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async with aiohttp.ClientSession() as session:
|
|
198
|
+
# Build URL with filters
|
|
199
|
+
url = f"{api_endpoint}/api/v1/deployments/api-key"
|
|
200
|
+
params = {}
|
|
201
|
+
if environment:
|
|
202
|
+
params['environment'] = environment
|
|
203
|
+
if current_project:
|
|
204
|
+
params['project_name'] = current_project
|
|
205
|
+
if limit and limit != 10:
|
|
206
|
+
params['per_page'] = min(limit, 100) # API limit
|
|
207
|
+
|
|
208
|
+
async with session.get(url, headers=headers, params=params, timeout=30) as response:
|
|
209
|
+
if response.status == 200:
|
|
210
|
+
data = await response.json()
|
|
211
|
+
|
|
212
|
+
# Handle paginated response from API (like in status.py)
|
|
213
|
+
if isinstance(data, dict) and 'deployments' in data:
|
|
214
|
+
deployments = data['deployments']
|
|
215
|
+
else:
|
|
216
|
+
deployments = data if isinstance(data, list) else []
|
|
217
|
+
|
|
218
|
+
# Return deployments in API format (no conversion needed)
|
|
219
|
+
return deployments, None
|
|
220
|
+
elif response.status == 401:
|
|
221
|
+
return [], "Invalid API key"
|
|
222
|
+
elif response.status == 403:
|
|
223
|
+
return [], "Access denied - check API key permissions"
|
|
224
|
+
else:
|
|
225
|
+
error_text = await response.text()
|
|
226
|
+
return [], f"API error {response.status}: {error_text[:100]}"
|
|
227
|
+
except Exception as e:
|
|
228
|
+
if "timeout" in str(e).lower():
|
|
229
|
+
return [], "Request timeout - check your connection"
|
|
230
|
+
elif "dns" in str(e).lower() or "name" in str(e).lower():
|
|
231
|
+
return [], f"Cannot resolve API endpoint - check DAITA_API_ENDPOINT setting"
|
|
232
|
+
else:
|
|
233
|
+
return [], f"Network error: {str(e)}"
|
|
234
|
+
|
|
235
|
+
def _get_deployment_id(deployment):
|
|
236
|
+
"""Generate short deployment ID."""
|
|
237
|
+
import hashlib
|
|
238
|
+
content = f"{deployment['deployed_at']}{deployment['environment']}"
|
|
239
|
+
return hashlib.md5(content.encode()).hexdigest()[:8]
|