pltr-cli 0.10.0__py3-none-any.whl → 0.12.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.
@@ -0,0 +1,333 @@
1
+ """
2
+ AIP Agents management commands for Foundry.
3
+ Provides commands for agent inspection, session management, and version control.
4
+ """
5
+
6
+ import typer
7
+ from typing import Optional
8
+ from rich.console import Console
9
+
10
+ from ..services.aip_agents import AipAgentsService
11
+ from ..utils.formatting import OutputFormatter
12
+ from ..utils.progress import SpinnerProgressTracker
13
+ from ..utils.pagination import PaginationConfig
14
+ from ..auth.base import ProfileNotFoundError, MissingCredentialsError
15
+ from ..utils.completion import (
16
+ complete_rid,
17
+ complete_profile,
18
+ complete_output_format,
19
+ cache_rid,
20
+ )
21
+
22
+ # Create main app and sub-apps
23
+ app = typer.Typer(help="Manage AIP Agents, sessions, and versions")
24
+ sessions_app = typer.Typer(help="Manage agent conversation sessions")
25
+ versions_app = typer.Typer(help="Manage agent versions")
26
+
27
+ # Add sub-apps
28
+ app.add_typer(sessions_app, name="sessions")
29
+ app.add_typer(versions_app, name="versions")
30
+
31
+ console = Console()
32
+ formatter = OutputFormatter(console)
33
+
34
+
35
+ @app.command("get")
36
+ def get_agent(
37
+ agent_rid: str = typer.Argument(
38
+ ...,
39
+ help="Agent Resource Identifier (e.g., ri.foundry.main.agent.abc123)",
40
+ autocompletion=complete_rid,
41
+ ),
42
+ version: Optional[str] = typer.Option(
43
+ None,
44
+ "--version",
45
+ "-v",
46
+ help="Agent version to retrieve (e.g., '1.0'). Defaults to latest published.",
47
+ ),
48
+ profile: Optional[str] = typer.Option(
49
+ None,
50
+ "--profile",
51
+ "-p",
52
+ help="Profile name",
53
+ autocompletion=complete_profile,
54
+ ),
55
+ format: str = typer.Option(
56
+ "table",
57
+ "--format",
58
+ "-f",
59
+ help="Output format (table, json, csv)",
60
+ autocompletion=complete_output_format,
61
+ ),
62
+ output: Optional[str] = typer.Option(
63
+ None, "--output", "-o", help="Output file path"
64
+ ),
65
+ ):
66
+ """
67
+ Get detailed information about an AIP Agent.
68
+
69
+ Retrieves agent configuration including name, description, parameters,
70
+ and version information.
71
+
72
+ Examples:
73
+
74
+ # Get latest published version of agent
75
+ pltr aip-agents get ri.foundry.main.agent.abc123
76
+
77
+ # Get specific version
78
+ pltr aip-agents get ri.foundry.main.agent.abc123 --version 1.5
79
+
80
+ # Output as JSON
81
+ pltr aip-agents get ri.foundry.main.agent.abc123 --format json
82
+ """
83
+ try:
84
+ cache_rid(agent_rid)
85
+
86
+ service = AipAgentsService(profile=profile)
87
+
88
+ with SpinnerProgressTracker().track_spinner(f"Fetching agent {agent_rid}..."):
89
+ agent = service.get_agent(agent_rid, version=version)
90
+
91
+ if output:
92
+ formatter.save_to_file(agent, output, format)
93
+ formatter.print_success(f"Agent information saved to {output}")
94
+ else:
95
+ formatter.display(agent, format)
96
+
97
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
98
+ formatter.print_error(f"Authentication error: {e}")
99
+ raise typer.Exit(1)
100
+ except ValueError as e:
101
+ formatter.print_error(f"Invalid request: {e}")
102
+ raise typer.Exit(1)
103
+ except Exception as e:
104
+ formatter.print_error(f"Failed to get agent: {e}")
105
+ raise typer.Exit(1)
106
+
107
+
108
+ @sessions_app.command("list")
109
+ def list_sessions(
110
+ agent_rid: str = typer.Argument(
111
+ ...,
112
+ help="Agent Resource Identifier",
113
+ autocompletion=complete_rid,
114
+ ),
115
+ profile: Optional[str] = typer.Option(
116
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
117
+ ),
118
+ format: str = typer.Option(
119
+ "table",
120
+ "--format",
121
+ "-f",
122
+ help="Output format (table, json, csv)",
123
+ autocompletion=complete_output_format,
124
+ ),
125
+ output: Optional[str] = typer.Option(
126
+ None, "--output", "-o", help="Output file path"
127
+ ),
128
+ page_size: Optional[int] = typer.Option(
129
+ None, "--page-size", help="Number of sessions per page"
130
+ ),
131
+ max_pages: Optional[int] = typer.Option(
132
+ 1, "--max-pages", help="Maximum number of pages to fetch (default: 1)"
133
+ ),
134
+ all: bool = typer.Option(
135
+ False, "--all", help="Fetch all available sessions (overrides --max-pages)"
136
+ ),
137
+ ):
138
+ """
139
+ List conversation sessions for an agent.
140
+
141
+ Only lists sessions created by this client (API). Sessions created
142
+ in AIP Agent Studio will not appear.
143
+
144
+ Examples:
145
+
146
+ # List first page of sessions
147
+ pltr aip-agents sessions list ri.foundry.main.agent.abc123
148
+
149
+ # List all sessions
150
+ pltr aip-agents sessions list ri.foundry.main.agent.abc123 --all
151
+
152
+ # List first 3 pages with 50 sessions each
153
+ pltr aip-agents sessions list ri.foundry.main.agent.abc123 \\
154
+ --page-size 50 --max-pages 3
155
+ """
156
+ try:
157
+ cache_rid(agent_rid)
158
+
159
+ service = AipAgentsService(profile=profile)
160
+ config = PaginationConfig(
161
+ page_size=page_size,
162
+ max_pages=max_pages,
163
+ fetch_all=all,
164
+ )
165
+
166
+ with SpinnerProgressTracker().track_spinner(
167
+ f"Fetching sessions for agent {agent_rid}..."
168
+ ):
169
+ result = service.list_sessions(agent_rid, config)
170
+
171
+ if not result.data:
172
+ console.print("[yellow]No sessions found for this agent[/yellow]")
173
+ return
174
+
175
+ if output:
176
+ formatter.format_paginated_output(result, format, output)
177
+ console.print(f"[green]Results saved to {output}[/green]")
178
+ else:
179
+ formatter.format_paginated_output(result, format)
180
+
181
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
182
+ formatter.print_error(f"Authentication error: {e}")
183
+ raise typer.Exit(1)
184
+ except Exception as e:
185
+ formatter.print_error(f"Failed to list sessions: {e}")
186
+ raise typer.Exit(1)
187
+
188
+
189
+ @sessions_app.command("get")
190
+ def get_session(
191
+ agent_rid: str = typer.Argument(
192
+ ...,
193
+ help="Agent Resource Identifier",
194
+ autocompletion=complete_rid,
195
+ ),
196
+ session_rid: str = typer.Argument(
197
+ ...,
198
+ help="Session Resource Identifier",
199
+ autocompletion=complete_rid,
200
+ ),
201
+ profile: Optional[str] = typer.Option(
202
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
203
+ ),
204
+ format: str = typer.Option(
205
+ "table",
206
+ "--format",
207
+ "-f",
208
+ help="Output format (table, json, csv)",
209
+ autocompletion=complete_output_format,
210
+ ),
211
+ output: Optional[str] = typer.Option(
212
+ None, "--output", "-o", help="Output file path"
213
+ ),
214
+ ):
215
+ """
216
+ Get detailed information about a conversation session.
217
+
218
+ Examples:
219
+
220
+ # Get session details
221
+ pltr aip-agents sessions get \\
222
+ ri.foundry.main.agent.abc123 \\
223
+ ri.foundry.main.session.xyz789
224
+
225
+ # Export session details to JSON
226
+ pltr aip-agents sessions get \\
227
+ ri.foundry.main.agent.abc123 \\
228
+ ri.foundry.main.session.xyz789 \\
229
+ --format json --output session.json
230
+ """
231
+ try:
232
+ cache_rid(agent_rid)
233
+ cache_rid(session_rid)
234
+
235
+ service = AipAgentsService(profile=profile)
236
+
237
+ with SpinnerProgressTracker().track_spinner(
238
+ f"Fetching session {session_rid}..."
239
+ ):
240
+ session = service.get_session(agent_rid, session_rid)
241
+
242
+ if output:
243
+ formatter.save_to_file(session, output, format)
244
+ formatter.print_success(f"Session information saved to {output}")
245
+ else:
246
+ formatter.display(session, format)
247
+
248
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
249
+ formatter.print_error(f"Authentication error: {e}")
250
+ raise typer.Exit(1)
251
+ except Exception as e:
252
+ formatter.print_error(f"Failed to get session: {e}")
253
+ raise typer.Exit(1)
254
+
255
+
256
+ @versions_app.command("list")
257
+ def list_versions(
258
+ agent_rid: str = typer.Argument(
259
+ ...,
260
+ help="Agent Resource Identifier",
261
+ autocompletion=complete_rid,
262
+ ),
263
+ profile: Optional[str] = typer.Option(
264
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
265
+ ),
266
+ format: str = typer.Option(
267
+ "table",
268
+ "--format",
269
+ "-f",
270
+ help="Output format (table, json, csv)",
271
+ autocompletion=complete_output_format,
272
+ ),
273
+ output: Optional[str] = typer.Option(
274
+ None, "--output", "-o", help="Output file path"
275
+ ),
276
+ page_size: Optional[int] = typer.Option(
277
+ None, "--page-size", help="Number of versions per page"
278
+ ),
279
+ max_pages: Optional[int] = typer.Option(
280
+ 1, "--max-pages", help="Maximum number of pages to fetch (default: 1)"
281
+ ),
282
+ all: bool = typer.Option(
283
+ False, "--all", help="Fetch all available versions (overrides --max-pages)"
284
+ ),
285
+ ):
286
+ """
287
+ List all versions for an AIP Agent.
288
+
289
+ Versions are returned in descending order (most recent first).
290
+
291
+ Examples:
292
+
293
+ # List first page of versions
294
+ pltr aip-agents versions list ri.foundry.main.agent.abc123
295
+
296
+ # List all versions
297
+ pltr aip-agents versions list ri.foundry.main.agent.abc123 --all
298
+
299
+ # Export all versions to CSV
300
+ pltr aip-agents versions list ri.foundry.main.agent.abc123 \\
301
+ --all --format csv --output versions.csv
302
+ """
303
+ try:
304
+ cache_rid(agent_rid)
305
+
306
+ service = AipAgentsService(profile=profile)
307
+ config = PaginationConfig(
308
+ page_size=page_size,
309
+ max_pages=max_pages,
310
+ fetch_all=all,
311
+ )
312
+
313
+ with SpinnerProgressTracker().track_spinner(
314
+ f"Fetching versions for agent {agent_rid}..."
315
+ ):
316
+ result = service.list_versions(agent_rid, config)
317
+
318
+ if not result.data:
319
+ console.print("[yellow]No versions found for this agent[/yellow]")
320
+ return
321
+
322
+ if output:
323
+ formatter.format_paginated_output(result, format, output)
324
+ console.print(f"[green]Results saved to {output}[/green]")
325
+ else:
326
+ formatter.format_paginated_output(result, format)
327
+
328
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
329
+ formatter.print_error(f"Authentication error: {e}")
330
+ raise typer.Exit(1)
331
+ except Exception as e:
332
+ formatter.print_error(f"Failed to list versions: {e}")
333
+ raise typer.Exit(1)
@@ -4,7 +4,8 @@ Connectivity management commands for Foundry connections and imports.
4
4
 
5
5
  import typer
6
6
  import json
7
- from typing import Optional
7
+ from pathlib import Path
8
+ from typing import List, Optional
8
9
  from rich.console import Console
9
10
 
10
11
  from ..services.connectivity import ConnectivityService
@@ -29,6 +30,53 @@ app.add_typer(connection_app, name="connection", help="Manage connections")
29
30
  app.add_typer(import_app, name="import", help="Manage data imports")
30
31
 
31
32
 
33
+ def _load_json_param(
34
+ json_str: Optional[str], file_path: Optional[str], param_name: str
35
+ ) -> dict:
36
+ """
37
+ Load JSON from either a string or a file.
38
+
39
+ Args:
40
+ json_str: JSON string (optional)
41
+ file_path: Path to JSON file (optional)
42
+ param_name: Name of parameter for error messages
43
+
44
+ Returns:
45
+ Parsed JSON dictionary
46
+
47
+ Raises:
48
+ typer.Exit: If neither or both are provided, or if parsing fails
49
+ """
50
+ if json_str and file_path:
51
+ console.print(
52
+ f"[red]Cannot specify both {param_name} and {param_name}-file[/red]"
53
+ )
54
+ raise typer.Exit(1)
55
+
56
+ if not json_str and not file_path:
57
+ console.print(
58
+ f"[red]Must specify either {param_name} or --{param_name}-file[/red]"
59
+ )
60
+ raise typer.Exit(1)
61
+
62
+ if file_path:
63
+ path = Path(file_path)
64
+ if not path.exists():
65
+ console.print(f"[red]File not found: {file_path}[/red]")
66
+ raise typer.Exit(1)
67
+ try:
68
+ json_str = path.read_text()
69
+ except Exception as e:
70
+ console.print(f"[red]Error reading {file_path}: {e}[/red]")
71
+ raise typer.Exit(1)
72
+
73
+ try:
74
+ return json.loads(json_str) # type: ignore[arg-type]
75
+ except json.JSONDecodeError as e:
76
+ console.print(f"[red]Invalid JSON for {param_name}: {e}[/red]")
77
+ raise typer.Exit(1)
78
+
79
+
32
80
  @connection_app.command("list")
33
81
  def list_connections(
34
82
  profile: Optional[str] = typer.Option(
@@ -104,6 +152,266 @@ def get_connection(
104
152
  raise typer.Exit(1)
105
153
 
106
154
 
155
+ @connection_app.command("create")
156
+ def create_connection(
157
+ display_name: str = typer.Argument(..., help="Display name for the connection"),
158
+ parent_folder_rid: str = typer.Argument(
159
+ ..., help="Parent folder Resource Identifier", autocompletion=complete_rid
160
+ ),
161
+ configuration: Optional[str] = typer.Argument(
162
+ None, help="Connection configuration in JSON format"
163
+ ),
164
+ worker: Optional[str] = typer.Argument(
165
+ None, help="Worker configuration in JSON format"
166
+ ),
167
+ config_file: Optional[str] = typer.Option(
168
+ None, "--config-file", help="Path to JSON file with connection configuration"
169
+ ),
170
+ worker_file: Optional[str] = typer.Option(
171
+ None, "--worker-file", help="Path to JSON file with worker configuration"
172
+ ),
173
+ profile: Optional[str] = typer.Option(
174
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
175
+ ),
176
+ format: str = typer.Option(
177
+ "table",
178
+ "--format",
179
+ "-f",
180
+ help="Output format (table, json, csv)",
181
+ autocompletion=complete_output_format,
182
+ ),
183
+ output: Optional[str] = typer.Option(
184
+ None, "--output", "-o", help="Output file path"
185
+ ),
186
+ ):
187
+ """Create a new connection.
188
+
189
+ Configuration and worker can be provided as JSON strings or via file options.
190
+ """
191
+ try:
192
+ cache_rid(parent_folder_rid)
193
+
194
+ # Load configuration from string or file
195
+ config_dict = _load_json_param(configuration, config_file, "configuration")
196
+ worker_dict = _load_json_param(worker, worker_file, "worker")
197
+
198
+ service = ConnectivityService(profile=profile)
199
+
200
+ with SpinnerProgressTracker().track_spinner("Creating connection..."):
201
+ connection = service.create_connection(
202
+ display_name=display_name,
203
+ parent_folder_rid=parent_folder_rid,
204
+ configuration=config_dict,
205
+ worker=worker_dict,
206
+ )
207
+
208
+ cache_rid(connection.get("rid", ""))
209
+ console.print(f"[green]Connection created: {connection.get('rid')}[/green]")
210
+ formatter.format_output([connection], format, output)
211
+
212
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
213
+ console.print(f"[red]Authentication error: {e}[/red]")
214
+ raise typer.Exit(1)
215
+ except Exception as e:
216
+ console.print(f"[red]Error creating connection: {e}[/red]")
217
+ raise typer.Exit(1)
218
+
219
+
220
+ @connection_app.command("get-config")
221
+ def get_connection_configuration(
222
+ connection_rid: str = typer.Argument(
223
+ ..., help="Connection Resource Identifier", autocompletion=complete_rid
224
+ ),
225
+ profile: Optional[str] = typer.Option(
226
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
227
+ ),
228
+ format: str = typer.Option(
229
+ "json",
230
+ "--format",
231
+ "-f",
232
+ help="Output format (table, json, csv)",
233
+ autocompletion=complete_output_format,
234
+ ),
235
+ output: Optional[str] = typer.Option(
236
+ None, "--output", "-o", help="Output file path"
237
+ ),
238
+ ):
239
+ """Get connection configuration."""
240
+ try:
241
+ cache_rid(connection_rid)
242
+
243
+ with SpinnerProgressTracker().track_spinner(
244
+ f"Fetching configuration for {connection_rid}..."
245
+ ):
246
+ service = ConnectivityService(profile=profile)
247
+ config = service.get_connection_configuration(connection_rid)
248
+
249
+ formatter.format_output([config], format, output)
250
+
251
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
252
+ console.print(f"[red]Authentication error: {e}[/red]")
253
+ raise typer.Exit(1)
254
+ except Exception as e:
255
+ console.print(f"[red]Error getting connection configuration: {e}[/red]")
256
+ raise typer.Exit(1)
257
+
258
+
259
+ @connection_app.command("update-secrets")
260
+ def update_connection_secrets(
261
+ connection_rid: str = typer.Argument(
262
+ ..., help="Connection Resource Identifier", autocompletion=complete_rid
263
+ ),
264
+ secrets_file: str = typer.Option(
265
+ ...,
266
+ "--secrets-file",
267
+ "-s",
268
+ help="Path to JSON file containing secrets (mapping secret names to values)",
269
+ ),
270
+ profile: Optional[str] = typer.Option(
271
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
272
+ ),
273
+ ):
274
+ """Update connection secrets.
275
+
276
+ Secrets must be provided via a file for security (to avoid exposure in shell
277
+ history or process listings).
278
+ """
279
+ try:
280
+ cache_rid(connection_rid)
281
+
282
+ # Load secrets from file
283
+ path = Path(secrets_file)
284
+ if not path.exists():
285
+ console.print(f"[red]Secrets file not found: {secrets_file}[/red]")
286
+ raise typer.Exit(1)
287
+
288
+ try:
289
+ secrets_content = path.read_text()
290
+ secrets_dict = json.loads(secrets_content)
291
+ except json.JSONDecodeError as e:
292
+ console.print(f"[red]Invalid JSON in secrets file: {e}[/red]")
293
+ raise typer.Exit(1)
294
+ except Exception as e:
295
+ console.print(f"[red]Error reading secrets file: {e}[/red]")
296
+ raise typer.Exit(1)
297
+
298
+ service = ConnectivityService(profile=profile)
299
+
300
+ with SpinnerProgressTracker().track_spinner("Updating secrets..."):
301
+ service.update_secrets(connection_rid, secrets_dict)
302
+
303
+ console.print(
304
+ f"[green]Secrets updated for connection: {connection_rid}[/green]"
305
+ )
306
+
307
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
308
+ console.print(f"[red]Authentication error: {e}[/red]")
309
+ raise typer.Exit(1)
310
+ except Exception as e:
311
+ console.print(f"[red]Error updating secrets: {e}[/red]")
312
+ raise typer.Exit(1)
313
+
314
+
315
+ @connection_app.command("update-export-settings")
316
+ def update_export_settings(
317
+ connection_rid: str = typer.Argument(
318
+ ..., help="Connection Resource Identifier", autocompletion=complete_rid
319
+ ),
320
+ settings: Optional[str] = typer.Argument(
321
+ None, help="Export settings in JSON format"
322
+ ),
323
+ settings_file: Optional[str] = typer.Option(
324
+ None, "--settings-file", help="Path to JSON file with export settings"
325
+ ),
326
+ profile: Optional[str] = typer.Option(
327
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
328
+ ),
329
+ ):
330
+ """Update connection export settings.
331
+
332
+ Settings can be provided as a JSON string or via --settings-file.
333
+ """
334
+ try:
335
+ cache_rid(connection_rid)
336
+
337
+ # Load settings from string or file
338
+ settings_dict = _load_json_param(settings, settings_file, "settings")
339
+
340
+ service = ConnectivityService(profile=profile)
341
+
342
+ with SpinnerProgressTracker().track_spinner("Updating export settings..."):
343
+ service.update_export_settings(connection_rid, settings_dict)
344
+
345
+ console.print(
346
+ f"[green]Export settings updated for connection: {connection_rid}[/green]"
347
+ )
348
+
349
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
350
+ console.print(f"[red]Authentication error: {e}[/red]")
351
+ raise typer.Exit(1)
352
+ except Exception as e:
353
+ console.print(f"[red]Error updating export settings: {e}[/red]")
354
+ raise typer.Exit(1)
355
+
356
+
357
+ @connection_app.command("upload-jdbc-drivers")
358
+ def upload_jdbc_drivers(
359
+ connection_rid: str = typer.Argument(
360
+ ..., help="Connection Resource Identifier", autocompletion=complete_rid
361
+ ),
362
+ driver_files: List[str] = typer.Argument(
363
+ ..., help="Path(s) to JAR file(s) to upload"
364
+ ),
365
+ profile: Optional[str] = typer.Option(
366
+ None, "--profile", "-p", help="Profile name", autocompletion=complete_profile
367
+ ),
368
+ format: str = typer.Option(
369
+ "table",
370
+ "--format",
371
+ "-f",
372
+ help="Output format (table, json, csv)",
373
+ autocompletion=complete_output_format,
374
+ ),
375
+ output: Optional[str] = typer.Option(
376
+ None, "--output", "-o", help="Output file path"
377
+ ),
378
+ ):
379
+ """Upload custom JDBC drivers to a connection.
380
+
381
+ Only JAR files are supported.
382
+ """
383
+ try:
384
+ cache_rid(connection_rid)
385
+
386
+ # Validate files exist and are JAR files before uploading
387
+ for driver_file in driver_files:
388
+ path = Path(driver_file)
389
+ if not path.exists():
390
+ console.print(f"[red]File not found: {driver_file}[/red]")
391
+ raise typer.Exit(1)
392
+ if path.suffix.lower() != ".jar":
393
+ console.print(f"[red]File must be a JAR file: {driver_file}[/red]")
394
+ raise typer.Exit(1)
395
+
396
+ service = ConnectivityService(profile=profile)
397
+ results = []
398
+
399
+ for driver_file in driver_files:
400
+ with SpinnerProgressTracker().track_spinner(f"Uploading {driver_file}..."):
401
+ result = service.upload_custom_jdbc_drivers(connection_rid, driver_file)
402
+ results.append(result)
403
+ console.print(f"[green]Uploaded: {driver_file}[/green]")
404
+
405
+ formatter.format_output(results, format, output)
406
+
407
+ except (ProfileNotFoundError, MissingCredentialsError) as e:
408
+ console.print(f"[red]Authentication error: {e}[/red]")
409
+ raise typer.Exit(1)
410
+ except Exception as e:
411
+ console.print(f"[red]Error uploading JDBC drivers: {e}[/red]")
412
+ raise typer.Exit(1)
413
+
414
+
107
415
  @import_app.command("file")
108
416
  def import_file(
109
417
  connection_rid: str = typer.Argument(