videosdkagent-cli 0.0.1__py2.py3-none-any.whl → 0.0.5__py2.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.
@@ -7,24 +7,38 @@ import os
7
7
  import re
8
8
  from videosdk_cli.utils.apis.deployment_client import DeploymentClient
9
9
  from videosdk_cli.utils.videosdk_yaml_helper import update_agent_config
10
- from videosdk_cli.utils.videosdk_yaml_helper import AgentConfig
11
- from rich.console import Console
10
+ from videosdk_cli.utils.videosdk_yaml_helper import AgentConfig, DeployConfig
12
11
  from InquirerPy import inquirer
13
12
  from rich.table import Table
14
13
  from videosdk_cli.utils.ui.kv_blocks import print_kv_blocks
15
- console = Console()
16
-
17
- async def init_agent(app_dir: Path, name: Optional[str] = None):
14
+ from videosdk_cli.utils.ui.theme import (
15
+ console,
16
+ print_success,
17
+ print_error,
18
+ print_warning,
19
+ print_info,
20
+ PRIMARY,
21
+ MUTED,
22
+ SUCCESS,
23
+ ERROR,
24
+ )
25
+
26
+
27
+ async def init_agent(
28
+ app_dir: Path, name: Optional[str] = None, template: Optional[str] = None
29
+ ):
18
30
  client = DeploymentClient()
19
31
 
20
- # Call backend
21
- response = await client.agent_init(name)
32
+ # Call backend - now creates both agent and deployment
33
+ response = await client.agent_init(name=name, template=template)
34
+ print(response)
22
35
 
23
36
  agent_id = response.get("agentId")
37
+ deployment_id = response.get("id")
24
38
  agent_name = response.get("name") or "agent-test"
25
39
 
26
- if not agent_id or not agent_name:
27
- raise RuntimeError("Invalid response from agent_init API")
40
+ if not agent_id or not deployment_id:
41
+ raise RuntimeError("Invalid response from deployment init API")
28
42
 
29
43
  # Build AgentConfig dataclass
30
44
  agent_config = AgentConfig(
@@ -32,125 +46,221 @@ async def init_agent(app_dir: Path, name: Optional[str] = None):
32
46
  name=agent_name,
33
47
  )
34
48
 
35
- # Update videosdk.yaml
49
+ # Build DeployConfig dataclass with deploymentId
50
+ deploy_config = DeployConfig(
51
+ id=deployment_id,
52
+ )
53
+
54
+ # Update videosdk.yaml with both agent and deploy config
36
55
  update_agent_config(
37
56
  app_dir=app_dir,
38
57
  agent_config=agent_config,
58
+ deploy_config=deploy_config,
39
59
  )
40
60
 
41
61
  return response
42
62
 
43
63
 
44
- async def list_deployment(deployment_id: Optional[str] = None,head: Optional[int] = None,tail: Optional[int] = None):
64
+ async def list_versions_manager(
65
+ agent_id: str,
66
+ deployment_id: str,
67
+ page: int = 1,
68
+ per_page: int = 10,
69
+ sort: int = -1,
70
+ ):
45
71
  client = DeploymentClient()
46
72
  try:
47
- response = await client.agent_list(deployment_id,head,tail)
48
- deployments = response.get("deployments", [])
73
+ response = await client.list_versions(
74
+ agent_id, deployment_id, page, per_page, sort
75
+ )
76
+ versions = response.get("versions", [])
49
77
 
50
- if not deployments:
51
- console.print("[bold red]No deployments found.[/bold red]")
78
+ if not versions:
79
+ print_warning("No versions found")
52
80
  return
53
81
 
54
- table = Table(title="Deployments", show_lines=True)
55
-
56
- table.add_column("Name", style="cyan", no_wrap=True)
57
- table.add_column("Region", style="green")
58
- table.add_column("Profile", style="magenta")
59
- table.add_column("Deployment ID", style="yellow",no_wrap=True)
82
+ table = Table(
83
+ title=f"[bold {PRIMARY}]Versions[/bold {PRIMARY}]",
84
+ show_lines=True,
85
+ header_style=f"bold {PRIMARY}",
86
+ border_style=MUTED,
87
+ )
88
+
89
+ table.add_column("Version ID", style=MUTED, no_wrap=True)
90
+ table.add_column("Name", style=PRIMARY, no_wrap=True)
91
+ table.add_column("Version Tag", style="white")
92
+ table.add_column("Region", style="white")
93
+ table.add_column("Profile", style="white")
94
+ table.add_column("Active", style=MUTED, no_wrap=True)
60
95
  table.add_column("Created At", style="white")
61
96
 
62
-
63
- for d in deployments:
64
- created = d["createdAt"].replace("T", " ").replace("Z", "")
97
+ for v in versions:
98
+ created = v.get("createdAt", "N/A").replace("T", " ").replace("Z", "")
65
99
 
66
100
  table.add_row(
67
- d["name"],
68
- d["region"],
69
- d["profile"],
70
- d["deploymentId"],
71
- created
101
+ v.get("id", "N/A"),
102
+ v.get("name", "N/A"),
103
+ v.get("versionTag", "N/A"),
104
+ v.get("region", "N/A"),
105
+ v.get("profile", "N/A"),
106
+ "Yes" if v.get("active") else "No",
107
+ created,
72
108
  )
73
-
109
+
74
110
  console.print(table)
75
111
  return response
76
112
  except Exception as e:
77
113
  raise e
78
114
 
79
- async def list_agents_manager(agent_id: Optional[str] = None,head: Optional[int] = None,tail: Optional[int] = None):
115
+
116
+ async def list_sessions_manager(
117
+ agent_id: str,
118
+ deployment_id: str,
119
+ version_id: Optional[str] = None,
120
+ room_id: Optional[str] = None,
121
+ session_id: Optional[str] = None,
122
+ page: int = 1,
123
+ per_page: int = 10,
124
+ sort: int = -1,
125
+ ):
80
126
  client = DeploymentClient()
81
127
  try:
82
- print(agent_id)
83
- response = await client.agent_list(agent_id,head,tail)
84
- deployments = response.get("deployments", [])
85
-
86
- if not deployments:
87
- console.print("[bold red]No deployments found.[/bold red]")
128
+ response = await client.agent_sessions_list(
129
+ agent_id=agent_id,
130
+ deployment_id=deployment_id,
131
+ version_id=version_id,
132
+ room_id=room_id,
133
+ session_id=session_id,
134
+ page=page,
135
+ per_page=per_page,
136
+ sort=sort,
137
+ )
138
+ sessions = response.get("sessions", [])
139
+ if not sessions:
140
+ print_warning("No sessions found")
88
141
  return
89
142
 
90
- table = Table(title="Deployments", show_lines=True)
91
-
92
- table.add_column("Name", style="cyan", no_wrap=True)
93
- table.add_column("Region", style="green")
94
- table.add_column("Profile", style="magenta")
95
- table.add_column("Deployment ID", style="yellow",no_wrap=True)
96
- table.add_column("Created At", style="white")
97
-
143
+ table = Table(
144
+ title=f"[bold {PRIMARY}]Sessions[/bold {PRIMARY}]",
145
+ show_lines=True,
146
+ header_style=f"bold {PRIMARY}",
147
+ border_style=MUTED,
148
+ )
149
+
150
+ # Columns: Session ID, Room ID, Version ID, Status, Duration
151
+ table.add_column("Session ID", style=PRIMARY, no_wrap=True)
152
+ table.add_column("Room ID", style="white", no_wrap=True)
153
+ table.add_column("Version ID", style=MUTED, no_wrap=True)
154
+ table.add_column("Status", style="white")
155
+ table.add_column("Duration", style="white")
156
+
157
+ for s in sessions:
158
+ # Compute duration as "Xm Ys" from start and end times, or "-" if unavailable
159
+ from datetime import datetime, timezone
160
+
161
+ start_raw = s.get("start")
162
+ end_raw = s.get("end")
163
+
164
+ if start_raw:
165
+ # Handle ISO format with potential Z suffix
166
+ start_raw = start_raw.replace("Z", "+00:00")
167
+ try:
168
+ start_dt = datetime.fromisoformat(start_raw)
169
+ except ValueError:
170
+ # Fallback for formats that might not match standard ISO exactly if needed
171
+ start_dt = datetime.strptime(
172
+ start_raw.split(".")[0], "%Y-%m-%dT%H:%M:%S"
173
+ )
98
174
 
99
- for d in deployments:
100
- created = d["createdAt"].replace("T", " ").replace("Z", "")
175
+ if end_raw:
176
+ end_raw = end_raw.replace("Z", "+00:00")
177
+ try:
178
+ end_dt = datetime.fromisoformat(end_raw)
179
+ except ValueError:
180
+ end_dt = datetime.strptime(
181
+ end_raw.split(".")[0], "%Y-%m-%dT%H:%M:%S"
182
+ )
183
+
184
+ delta = end_dt - start_dt
185
+ else:
186
+ # For running sessions, duration is up to now
187
+ end_dt = datetime.now(timezone.utc)
188
+ # Ensure start_dt is timezone-aware if end_dt is
189
+ if start_dt.tzinfo is None:
190
+ start_dt = start_dt.replace(tzinfo=timezone.utc)
191
+ delta = end_dt - start_dt
192
+
193
+ total_seconds = int(delta.total_seconds())
194
+ minutes = total_seconds // 60
195
+ seconds = total_seconds % 60
196
+ duration = f"{minutes}m {seconds}s"
197
+ else:
198
+ duration = "-"
199
+
200
+ # Set display status: running if ended is None, else ended
201
+ display_status = "running" if end_raw is None else "ended"
101
202
 
102
203
  table.add_row(
103
- d["name"],
104
- d["region"],
105
- d["profile"],
106
- d["deploymentId"],
107
- created
204
+ s.get("sessionId", "N/A"),
205
+ s.get("roomId", "N/A"),
206
+ s.get("versionId", "N/A"),
207
+ display_status,
208
+ duration,
108
209
  )
109
-
210
+
110
211
  console.print(table)
111
212
  return response
213
+
112
214
  except Exception as e:
113
215
  raise e
114
216
 
115
- async def describe_agent_manager(agent_id:str,deployment_id:Optional[str] = None):
217
+
218
+ async def describe_version_manager(agent_id: str, version_id: Optional[str] = None):
116
219
  client = DeploymentClient()
117
220
  try:
118
- response = await client.agent_describe(agent_id,deployment_id)
221
+ response = await client.describe_version(agent_id, version_id)
222
+ # print(response)
119
223
  data_to_print = {}
120
224
  if response:
121
225
  data_to_print = {
122
- "Agent ID": response.get("agentId",'N/A'),
123
- "Name": response.get("name",'N/A'),
124
- "Region": response.get("region",'N/A'),
125
- "Profile": response.get("profile",'N/A'),
126
- "Deployment ID": response.get("deploymentId",'N/A'),
127
- "Created At": response.get("createdAt",'N/A').replace("T", " ").replace("Z", ""),
128
- "minReplica": response.get("minReplica",'N/A'),
129
- "maxReplica": response.get("maxReplica",'N/A'),
130
- "imageCR": response.get("image",{}).get("imageCR",'N/A'),
131
- "imageUrl": response.get("image",{}).get("imageUrl",'N/A'),
132
- "Active": response.get("active",'N/A'),
226
+ "Agent ID": response.get("agentId", "N/A"),
227
+ "Name": response.get("name", "N/A"),
228
+ "Version Tag": response.get("versionTag", "N/A"),
229
+ "Region": response.get("region", "N/A"),
230
+ "Profile": response.get("profile", "N/A"),
231
+ "Version ID": response.get("id", "N/A"),
232
+ "Deployment ID": response.get("deploymentId", "N/A"),
233
+ "Created At": response.get("createdAt", "N/A")
234
+ .replace("T", " ")
235
+ .replace("Z", ""),
236
+ "minReplica": response.get("minReplica", "N/A"),
237
+ "maxReplica": response.get("maxReplica", "N/A"),
238
+ "Registry": response.get("image", {}).get("imageCR", "N/A"),
239
+ "Image": response.get("image", {}).get("imageUrl", "N/A"),
240
+ "Active": response.get("active", "N/A"),
241
+ "Status": response.get("status", "N/A"),
133
242
  }
134
243
 
135
244
  print_kv_blocks([data_to_print])
136
-
245
+
137
246
  except Exception as e:
138
247
  raise e
139
248
 
249
+
140
250
  def parse_env_file(env_file: Path) -> dict:
141
251
  if not env_file.exists():
142
252
  raise click.ClickException("Env file does not exist")
143
-
253
+
144
254
  env_vars = dotenv_values(env_file)
145
255
 
146
256
  if not env_vars:
147
257
  raise click.ClickException("Env file is empty or invalid")
148
-
149
258
 
150
259
  # Convert OrderedDict -> dict
151
260
  return dict(env_vars)
152
261
 
153
- async def secret_set_manager(name:str,file:Optional[str] = None):
262
+
263
+ async def secret_set_manager(name: str, file: Optional[str] = None):
154
264
  client = DeploymentClient()
155
265
  try:
156
266
  console.print(f"Secret Name: [green]{name}[/green]")
@@ -215,10 +325,11 @@ async def secret_set_manager(name:str,file:Optional[str] = None):
215
325
  if action == "Cancel":
216
326
  console.print("[yellow]Cancelled. No secrets were saved.[/yellow]")
217
327
  return
218
-
328
+
219
329
  console.print("\nSaving secrets...")
220
330
  response = await client.secret_set(name, secrets)
221
331
  console.print("Secrets saved successfully.")
332
+ return response
222
333
  except Exception as e:
223
334
  raise e
224
335
 
@@ -226,77 +337,85 @@ async def secret_set_manager(name:str,file:Optional[str] = None):
226
337
  async def list_secret_manager():
227
338
  client = DeploymentClient()
228
339
  try:
229
- console.print("[bold blue]Listing secrets...[/bold blue]")
230
340
  response = await client.secret_list()
231
341
  data = response.get("data", [])
232
342
 
233
343
  if not data:
234
- console.print("[bold red]No secrets found.[/bold red]")
344
+ print_warning("No secrets found")
235
345
  return
236
346
 
237
- table = Table(title="Secrets", show_lines=True)
347
+ table = Table(
348
+ title=f"[bold {PRIMARY}]Secrets[/bold {PRIMARY}]",
349
+ show_lines=True,
350
+ header_style=f"bold {PRIMARY}",
351
+ border_style=MUTED,
352
+ )
238
353
 
239
- table.add_column("name", style="cyan", no_wrap=True)
240
- table.add_column("secretId", style="green")
241
- table.add_column("type", style="magenta")
354
+ table.add_column("Name", style=PRIMARY, no_wrap=True)
355
+ # table.add_column("Secret ID", style=MUTED)
356
+ table.add_column("Type", style="white")
242
357
 
243
358
  for d in data:
244
- table.add_row(
245
- d.get('name','N/A'),
246
- d.get('secretId','N/A'),
247
- d.get('type','N/A'),
359
+ table.add_row(
360
+ d.get("name", "N/A"),
361
+ # d.get("id", "N/A"),
362
+ d.get("type", "N/A"),
248
363
  )
249
364
 
250
365
  console.print(table)
251
- console.print("Secrets listed successfully.")
366
+ print_success("Secrets listed successfully")
252
367
  except Exception as e:
253
368
  raise e
254
369
 
370
+
255
371
  async def remove_secret_set(name: str):
256
372
  client = DeploymentClient()
257
373
  try:
258
- console.print("[bold blue]Removing secret...[/bold blue]")
259
374
  response = await client.secret_remove(name)
260
- console.print("Secret removed successfully.")
375
+ print_success("Secret removed successfully")
261
376
  except Exception as e:
262
377
  raise e
263
378
 
379
+
264
380
  async def describe_secret_set(name: str):
265
381
  client = DeploymentClient()
266
382
  try:
267
- console.print("[bold blue]Getting secret...[/bold blue]")
268
383
  response = await client.secret_get(name)
269
384
  data_to_print = {}
270
- data=response.get("data", {})
385
+ data = response.get("data", {})
271
386
  if data:
272
387
  data_to_print = {
273
- "Name": data.get("name",'N/A'),
274
- "Secret ID": data.get("secretId",'N/A'),
275
- "type": data.get("type",'N/A'),
388
+ "Name": data.get("name", "N/A"),
389
+ "Secret ID": data.get("secretId", "N/A"),
390
+ "Type": data.get("type", "N/A"),
276
391
  }
277
392
  print_kv_blocks([data_to_print])
278
- # 2️⃣ Keys table
393
+
394
+ # Keys table
279
395
  keys = data.get("keys", {})
280
396
 
281
397
  if not keys:
282
- console.print("\n[dim]No keys found[/dim]")
398
+ print_info("No keys found")
283
399
  return
284
400
 
285
- table = Table(title="Secret Keys", show_header=True, header_style="bold")
401
+ table = Table(
402
+ title=f"[bold {PRIMARY}]Secret Keys[/bold {PRIMARY}]",
403
+ show_header=True,
404
+ header_style=f"bold {PRIMARY}",
405
+ border_style=MUTED,
406
+ )
286
407
 
287
- table.add_column("Key", style="cyan", no_wrap=True)
288
- table.add_column("Value", style="green")
408
+ table.add_column("Key", style=PRIMARY, no_wrap=True)
409
+ table.add_column("Value", style="white")
289
410
 
290
411
  for k in keys:
291
- table.add_row(
292
- k,
293
- keys.get(k,'N/A')
294
- )
412
+ table.add_row(k, keys.get(k, "N/A"))
295
413
 
296
414
  console.print(table)
297
415
  except Exception as e:
298
416
  raise e
299
417
 
418
+
300
419
  async def add_secret_set(name: str):
301
420
  client = DeploymentClient()
302
421
  try:
@@ -333,20 +452,21 @@ async def add_secret_set(name: str):
333
452
  ).execute()
334
453
 
335
454
  if action == "Cancel":
336
- console.print("Cancelled. No secrets were saved.", fg="yellow")
455
+ console.print("[yellow]Cancelled. No secrets were saved.[/yellow]")
337
456
  return
338
-
457
+
339
458
  response = await client.secret_add_key(name, secrets)
340
-
459
+
341
460
  console.print("Secret added successfully.")
342
461
  except Exception as e:
343
462
  raise e
344
463
 
464
+
345
465
  async def remove_secret_set_key(name: str):
346
466
  client = DeploymentClient()
347
467
  try:
348
468
  console.print("[bold blue]Removing secret...[/bold blue]")
349
- keys=[]
469
+ keys = []
350
470
  while True:
351
471
  key = click.prompt("Enter key", type=str)
352
472
  keys.append(key)
@@ -362,20 +482,68 @@ async def remove_secret_set_key(name: str):
362
482
  if not keys:
363
483
  console.print("No keys provided.")
364
484
  return
365
- response = await client.secret_remove_key(name,keys)
485
+ response = await client.secret_remove_key(name, keys)
366
486
  console.print("Secret removed successfully.")
367
487
  except Exception as e:
368
488
  raise e
369
489
 
490
+
370
491
  async def image_pull_secret_manager(name: str):
371
492
  client = DeploymentClient()
372
493
  try:
373
494
  console.print("[bold blue]Setting image pull secret...[/bold blue]")
374
495
  console.print(f"Secret Name: [green]{name}[/green]")
375
- server =click.prompt("Enter server name", type=str)
376
- username =click.prompt("Enter username", type=str)
377
- password =click.prompt("Enter password", type=str,hide_input=True)
378
- response = await client.secret_set(name,{"serverName":server,"USERNAME":username,"PASSWORD":password},type="IMAGE_PULL")
496
+ server = click.prompt("Enter server url", type=str)
497
+ username = click.prompt("Enter username", type=str)
498
+ password = click.prompt("Enter password", type=str, hide_input=True)
499
+ response = await client.secret_set(
500
+ name,
501
+ {"serverName": server, "USERNAME": username, "PASSWORD": password},
502
+ type="IMAGE_PULL",
503
+ )
379
504
  console.print("Image pull secret set successfully.")
380
505
  except Exception as e:
381
506
  raise e
507
+
508
+
509
+ async def version_logs_manager(
510
+ agent_id: str,
511
+ deployment_id: str,
512
+ version_id: Optional[str] = None,
513
+ limit: Optional[int] = None,
514
+ ):
515
+ client = DeploymentClient()
516
+ try:
517
+ response = await client.agent_console_logs(
518
+ deployment_id=deployment_id,
519
+ agent_id=agent_id,
520
+ version_id=version_id,
521
+ limit=limit,
522
+ )
523
+ logs = response.get("logs", [])
524
+
525
+ if not logs:
526
+ print_warning("No logs found")
527
+ return
528
+
529
+ # Print logs in a readable format
530
+ for log_entry in logs:
531
+ timestamp = log_entry.get("timestamp", "")
532
+ message = log_entry.get("log", "")
533
+ level = log_entry.get("level", "info").upper()
534
+
535
+ # Format timestamp
536
+ if timestamp:
537
+ timestamp = timestamp.replace("T", " ").replace("Z", "")
538
+
539
+ # Color based on level
540
+ if level == "ERROR":
541
+ console.print(f"[{level}] {message}")
542
+ elif level == "WARN" or level == "WARNING":
543
+ console.print(f"[{level}] {message}")
544
+ else:
545
+ console.print(f"[{level}] {message}")
546
+
547
+ return response
548
+ except Exception as e:
549
+ raise e