glaip-sdk 0.0.3__py3-none-any.whl → 0.0.5__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.
- glaip_sdk/__init__.py +5 -5
- glaip_sdk/branding.py +146 -0
- glaip_sdk/cli/__init__.py +1 -1
- glaip_sdk/cli/agent_config.py +82 -0
- glaip_sdk/cli/commands/__init__.py +3 -3
- glaip_sdk/cli/commands/agents.py +786 -271
- glaip_sdk/cli/commands/configure.py +19 -19
- glaip_sdk/cli/commands/mcps.py +151 -141
- glaip_sdk/cli/commands/models.py +1 -1
- glaip_sdk/cli/commands/tools.py +252 -178
- glaip_sdk/cli/display.py +244 -0
- glaip_sdk/cli/io.py +106 -0
- glaip_sdk/cli/main.py +27 -20
- glaip_sdk/cli/resolution.py +59 -0
- glaip_sdk/cli/utils.py +372 -213
- glaip_sdk/cli/validators.py +235 -0
- glaip_sdk/client/__init__.py +3 -224
- glaip_sdk/client/agents.py +632 -171
- glaip_sdk/client/base.py +66 -4
- glaip_sdk/client/main.py +226 -0
- glaip_sdk/client/mcps.py +143 -18
- glaip_sdk/client/tools.py +327 -104
- glaip_sdk/config/constants.py +10 -1
- glaip_sdk/models.py +43 -3
- glaip_sdk/rich_components.py +29 -0
- glaip_sdk/utils/__init__.py +18 -171
- glaip_sdk/utils/agent_config.py +181 -0
- glaip_sdk/utils/client_utils.py +159 -79
- glaip_sdk/utils/display.py +100 -0
- glaip_sdk/utils/general.py +94 -0
- glaip_sdk/utils/import_export.py +140 -0
- glaip_sdk/utils/rendering/formatting.py +6 -1
- glaip_sdk/utils/rendering/renderer/__init__.py +67 -8
- glaip_sdk/utils/rendering/renderer/base.py +340 -247
- glaip_sdk/utils/rendering/renderer/debug.py +3 -2
- glaip_sdk/utils/rendering/renderer/panels.py +11 -10
- glaip_sdk/utils/rendering/steps.py +1 -1
- glaip_sdk/utils/resource_refs.py +192 -0
- glaip_sdk/utils/rich_utils.py +29 -0
- glaip_sdk/utils/serialization.py +285 -0
- glaip_sdk/utils/validation.py +273 -0
- {glaip_sdk-0.0.3.dist-info → glaip_sdk-0.0.5.dist-info}/METADATA +6 -5
- glaip_sdk-0.0.5.dist-info/RECORD +55 -0
- glaip_sdk/cli/commands/init.py +0 -177
- glaip_sdk-0.0.3.dist-info/RECORD +0 -40
- {glaip_sdk-0.0.3.dist-info → glaip_sdk-0.0.5.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.3.dist-info → glaip_sdk-0.0.5.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/display.py
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""CLI display utilities for success/failure panels and Rich renderers.
|
|
2
|
+
|
|
3
|
+
This module handles all display-related functionality for CLI commands,
|
|
4
|
+
including success messages, error handling, and output formatting.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
from rich.panel import Panel
|
|
16
|
+
from rich.text import Text
|
|
17
|
+
|
|
18
|
+
from glaip_sdk.rich_components import AIPPanel
|
|
19
|
+
|
|
20
|
+
console = Console()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def display_creation_success(
|
|
24
|
+
resource_type: str, resource_name: str, resource_id: str, **additional_fields
|
|
25
|
+
) -> Panel:
|
|
26
|
+
"""Create standardized success message for resource creation.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
|
|
30
|
+
resource_name: Name of the created resource
|
|
31
|
+
resource_id: ID of the created resource
|
|
32
|
+
**additional_fields: Additional fields to display
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Rich Panel object for display
|
|
36
|
+
"""
|
|
37
|
+
# Build additional fields display
|
|
38
|
+
fields_display = ""
|
|
39
|
+
if additional_fields:
|
|
40
|
+
fields_display = "\n" + "\n".join(
|
|
41
|
+
f"{key}: {value}" for key, value in additional_fields.items()
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return AIPPanel(
|
|
45
|
+
f"[green]✅ {resource_type} '{resource_name}' created successfully![/green]\n\n"
|
|
46
|
+
f"ID: {resource_id}{fields_display}",
|
|
47
|
+
title=f"🤖 {resource_type} Created",
|
|
48
|
+
border_style="green",
|
|
49
|
+
padding=(0, 1),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def display_update_success(resource_type: str, resource_name: str) -> Text:
|
|
54
|
+
"""Create standardized success message for resource update.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
|
|
58
|
+
resource_name: Name of the updated resource
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Rich Text object for display
|
|
62
|
+
"""
|
|
63
|
+
return Text(
|
|
64
|
+
f"[green]✅ {resource_type} '{resource_name}' updated successfully[/green]"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def display_deletion_success(resource_type: str, resource_name: str) -> Text:
|
|
69
|
+
"""Create standardized success message for resource deletion.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
|
|
73
|
+
resource_name: Name of the deleted resource
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Rich Text object for display
|
|
77
|
+
"""
|
|
78
|
+
return Text(
|
|
79
|
+
f"[green]✅ {resource_type} '{resource_name}' deleted successfully[/green]"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def display_api_error(error: Exception, operation: str = "operation") -> None:
|
|
84
|
+
"""Display standardized API error message.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
error: The exception that occurred
|
|
88
|
+
operation: Description of the operation that failed
|
|
89
|
+
"""
|
|
90
|
+
error_type = type(error).__name__
|
|
91
|
+
console.print(Text(f"[red]Error during {operation}: {error}[/red]"))
|
|
92
|
+
console.print(Text(f"[dim]Error type: {error_type}[/dim]"))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def print_api_error(e: Exception) -> None:
|
|
96
|
+
"""Print API error with consistent formatting for both JSON and Rich views.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
e: The exception to format and display
|
|
100
|
+
|
|
101
|
+
Notes:
|
|
102
|
+
- Extracts status_code, error_type, and payload from APIError exceptions
|
|
103
|
+
- Provides consistent error reporting across CLI commands
|
|
104
|
+
- Handles both JSON and Rich output formats
|
|
105
|
+
"""
|
|
106
|
+
if hasattr(e, "__dict__"): # Check if it's an APIError-like object
|
|
107
|
+
error_info = {
|
|
108
|
+
"error": str(e),
|
|
109
|
+
"status_code": getattr(e, "status_code", None),
|
|
110
|
+
"error_type": getattr(e, "error_type", None),
|
|
111
|
+
"details": getattr(e, "payload", None),
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Filter out None values
|
|
115
|
+
error_info = {k: v for k, v in error_info.items() if v is not None}
|
|
116
|
+
|
|
117
|
+
# For JSON view, just return the structured error
|
|
118
|
+
# (CLI commands handle the JSON formatting)
|
|
119
|
+
if hasattr(e, "status_code"):
|
|
120
|
+
console.print(f"[red]API Error: {e}[/red]")
|
|
121
|
+
if hasattr(e, "status_code"):
|
|
122
|
+
console.print(f"[yellow]Status: {e.status_code}[/yellow]")
|
|
123
|
+
if hasattr(e, "payload"):
|
|
124
|
+
console.print(f"[yellow]Details: {e.payload}[/yellow]")
|
|
125
|
+
else:
|
|
126
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
127
|
+
else:
|
|
128
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
_MISSING = object()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def build_resource_result_data(resource: Any, fields: list[str]) -> dict[str, Any]:
|
|
135
|
+
"""Return a normalized mapping of ``fields`` extracted from ``resource``."""
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
field: _normalise_field_value(field, _safe_get_attr(resource, field))
|
|
139
|
+
for field in fields
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _safe_get_attr(resource: Any, field: str) -> Any:
|
|
144
|
+
try:
|
|
145
|
+
return getattr(resource, field, _MISSING)
|
|
146
|
+
except Exception:
|
|
147
|
+
return _MISSING
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _normalise_field_value(field: str, value: Any) -> Any:
|
|
151
|
+
if value is _MISSING:
|
|
152
|
+
return "N/A"
|
|
153
|
+
if hasattr(value, "_mock_name"):
|
|
154
|
+
return "N/A"
|
|
155
|
+
if field == "id":
|
|
156
|
+
return str(value)
|
|
157
|
+
return value
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def handle_json_output(
|
|
161
|
+
ctx, data: Any = None, error: Exception = None
|
|
162
|
+
) -> None: # pragma: no cover - formatting covered via integration tests
|
|
163
|
+
"""Handle JSON output format for CLI commands.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
ctx: Click context
|
|
167
|
+
data: Data to output (for successful operations)
|
|
168
|
+
error: Error to output (for failed operations)
|
|
169
|
+
"""
|
|
170
|
+
ctx_obj = getattr(ctx, "obj", {}) if ctx is not None else {}
|
|
171
|
+
if not isinstance(ctx_obj, dict):
|
|
172
|
+
ctx_obj = {}
|
|
173
|
+
|
|
174
|
+
if ctx_obj.get("view") == "json":
|
|
175
|
+
if error:
|
|
176
|
+
output_data = {"error": str(error)}
|
|
177
|
+
# Add additional error details if available
|
|
178
|
+
if hasattr(error, "status_code"):
|
|
179
|
+
output_data["status_code"] = error.status_code
|
|
180
|
+
if hasattr(error, "error_type"):
|
|
181
|
+
output_data["error_type"] = error.error_type
|
|
182
|
+
if hasattr(error, "payload"):
|
|
183
|
+
output_data["details"] = error.payload
|
|
184
|
+
else:
|
|
185
|
+
output_data = data if data is not None else {"success": True}
|
|
186
|
+
|
|
187
|
+
click.echo(json.dumps(output_data, indent=2, default=str))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def handle_rich_output(ctx, rich_content: Any = None) -> None:
|
|
191
|
+
"""Handle Rich output format for CLI commands.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
ctx: Click context
|
|
195
|
+
rich_content: Rich content to display
|
|
196
|
+
"""
|
|
197
|
+
ctx_obj = getattr(ctx, "obj", {}) if ctx is not None else {}
|
|
198
|
+
if not isinstance(ctx_obj, dict):
|
|
199
|
+
ctx_obj = {}
|
|
200
|
+
|
|
201
|
+
if ctx_obj.get("view") != "json" and rich_content:
|
|
202
|
+
console.print(rich_content)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def display_confirmation_prompt(resource_type: str, resource_name: str) -> bool:
|
|
206
|
+
"""Display standardized confirmation prompt for destructive operations.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
|
|
210
|
+
resource_name: Name of the resource
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
True if user confirms, False otherwise
|
|
214
|
+
"""
|
|
215
|
+
if not click.confirm(
|
|
216
|
+
f"Are you sure you want to delete {resource_type.lower()} '{resource_name}'?"
|
|
217
|
+
):
|
|
218
|
+
if console.is_terminal:
|
|
219
|
+
console.print(Text("Deletion cancelled."))
|
|
220
|
+
return False
|
|
221
|
+
return True
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def display_agent_run_suggestions(agent: Any) -> Panel:
|
|
225
|
+
"""Return a panel with post-creation suggestions for an agent."""
|
|
226
|
+
|
|
227
|
+
return AIPPanel(
|
|
228
|
+
f"[bold blue]💡 Next Steps:[/bold blue]\n\n"
|
|
229
|
+
f"🚀 Run this agent:\n"
|
|
230
|
+
f' [green]aip agents run {agent.id} "Your message here"[/green]\n\n'
|
|
231
|
+
f"📋 Or use the agent name:\n"
|
|
232
|
+
f' [green]aip agents run "{agent.name}" "Your message here"[/green]\n\n'
|
|
233
|
+
f"🔧 Available options:\n"
|
|
234
|
+
f" [dim]--chat-history[/dim] Include previous conversation\n"
|
|
235
|
+
f" [dim]--file[/dim] Attach files\n"
|
|
236
|
+
f" [dim]--input[/dim] Alternative input method\n"
|
|
237
|
+
f" [dim]--timeout[/dim] Set execution timeout\n"
|
|
238
|
+
f" [dim]--save[/dim] Save transcript to file\n"
|
|
239
|
+
f" [dim]--verbose[/dim] Show detailed execution\n\n"
|
|
240
|
+
f"💡 [dim]Input text can be positional OR use --input flag (both work!)[/dim]",
|
|
241
|
+
title="🤖 Ready to Run Agent",
|
|
242
|
+
border_style="blue",
|
|
243
|
+
padding=(0, 1),
|
|
244
|
+
)
|
glaip_sdk/cli/io.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""CLI I/O utilities for file import/export orchestration.
|
|
2
|
+
|
|
3
|
+
This module handles file operations and network requests for CLI commands,
|
|
4
|
+
wrapping core serialization utilities with Click-friendly error handling.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from glaip_sdk.utils.serialization import (
|
|
16
|
+
collect_attributes_for_export,
|
|
17
|
+
load_resource_from_file,
|
|
18
|
+
write_resource_export,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_resource_from_file_with_validation(
|
|
23
|
+
file_path: Path, resource_type: str
|
|
24
|
+
) -> dict[str, Any]:
|
|
25
|
+
"""Load resource data from JSON or YAML file with CLI-friendly error handling.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
file_path: Path to the file
|
|
29
|
+
resource_type: Type of resource (for error messages)
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Dictionary with resource data
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
click.ClickException: If file operations fail
|
|
36
|
+
"""
|
|
37
|
+
try:
|
|
38
|
+
return load_resource_from_file(file_path)
|
|
39
|
+
except FileNotFoundError:
|
|
40
|
+
raise click.ClickException(f"File not found: {file_path}")
|
|
41
|
+
except ValueError as e:
|
|
42
|
+
raise click.ClickException(f"Invalid {resource_type.lower()} file format: {e}")
|
|
43
|
+
except Exception as e:
|
|
44
|
+
raise click.ClickException(f"Failed to load {resource_type.lower()} file: {e}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def export_resource_to_file_with_validation(
|
|
48
|
+
resource: Any, file_path: Path, format: str = "json"
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Export resource to file with CLI-friendly error handling.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
resource: Resource object to export
|
|
54
|
+
file_path: Path to export file
|
|
55
|
+
format: Export format ("json" or "yaml")
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
click.ClickException: If export operations fail
|
|
59
|
+
"""
|
|
60
|
+
try:
|
|
61
|
+
# Get all available resource attributes dynamically
|
|
62
|
+
export_data = collect_attributes_for_export(resource)
|
|
63
|
+
write_resource_export(file_path, export_data, format)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
raise click.ClickException(f"Failed to export resource: {e}")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def fetch_raw_resource_details(client, resource, resource_type: str):
|
|
69
|
+
"""Fetch raw resource details directly from API to preserve ALL fields.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
client: API client
|
|
73
|
+
resource: Resource object
|
|
74
|
+
resource_type: Type of resource ("agents", "tools", "mcps")
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Raw API response data or None if failed
|
|
78
|
+
|
|
79
|
+
Notes:
|
|
80
|
+
This is CLI-specific functionality for displaying comprehensive resource details.
|
|
81
|
+
"""
|
|
82
|
+
from rich.console import Console
|
|
83
|
+
|
|
84
|
+
console = Console()
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
resource_id = str(getattr(resource, "id", "")).strip()
|
|
88
|
+
if resource_id:
|
|
89
|
+
# Make direct API call to get raw response
|
|
90
|
+
response = client.http_client.get(f"/{resource_type}/{resource_id}")
|
|
91
|
+
response.raise_for_status()
|
|
92
|
+
raw_response = response.json()
|
|
93
|
+
|
|
94
|
+
# If it's a wrapped response (success/data/message), extract the data
|
|
95
|
+
if isinstance(raw_response, dict) and "data" in raw_response:
|
|
96
|
+
return raw_response["data"]
|
|
97
|
+
else:
|
|
98
|
+
# Direct response
|
|
99
|
+
return raw_response
|
|
100
|
+
except Exception as e:
|
|
101
|
+
console.print(
|
|
102
|
+
f"[yellow]Failed to fetch raw {resource_type} details: {e}[/yellow]"
|
|
103
|
+
)
|
|
104
|
+
# Fall back to regular method
|
|
105
|
+
return None
|
|
106
|
+
return None
|
glaip_sdk/cli/main.py
CHANGED
|
@@ -10,22 +10,21 @@ import sys
|
|
|
10
10
|
|
|
11
11
|
import click
|
|
12
12
|
from rich.console import Console
|
|
13
|
-
from rich.panel import Panel
|
|
14
|
-
from rich.table import Table
|
|
15
13
|
|
|
16
14
|
from glaip_sdk import Client
|
|
17
15
|
from glaip_sdk._version import __version__ as _SDK_VERSION
|
|
16
|
+
from glaip_sdk.branding import AIPBranding
|
|
18
17
|
from glaip_sdk.cli.commands.agents import agents_group
|
|
19
18
|
from glaip_sdk.cli.commands.configure import (
|
|
20
19
|
config_group,
|
|
21
20
|
configure_command,
|
|
22
21
|
load_config,
|
|
23
22
|
)
|
|
24
|
-
from glaip_sdk.cli.commands.init import init_command
|
|
25
23
|
from glaip_sdk.cli.commands.mcps import mcps_group
|
|
26
24
|
from glaip_sdk.cli.commands.models import models_group
|
|
27
25
|
from glaip_sdk.cli.commands.tools import tools_group
|
|
28
26
|
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
|
|
27
|
+
from glaip_sdk.rich_components import AIPPanel, AIPTable
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
@click.group()
|
|
@@ -43,17 +42,17 @@ from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
|
|
|
43
42
|
@click.option("--no-tty", is_flag=True, help="Disable TTY renderer")
|
|
44
43
|
@click.pass_context
|
|
45
44
|
def main(ctx, api_url, api_key, timeout, view, no_tty):
|
|
46
|
-
"""AIP SDK Command Line Interface.
|
|
45
|
+
"""GL AIP SDK Command Line Interface.
|
|
47
46
|
|
|
48
|
-
A comprehensive CLI for managing
|
|
47
|
+
A comprehensive CLI for managing GL AIP resources including
|
|
49
48
|
agents, tools, MCPs, and more.
|
|
50
49
|
|
|
51
50
|
Examples:
|
|
51
|
+
aip version # Show detailed version info
|
|
52
52
|
aip configure # Configure credentials
|
|
53
53
|
aip agents list # List all agents
|
|
54
54
|
aip tools create my_tool.py # Create a new tool
|
|
55
|
-
aip agents run my-agent "Hello" # Run an agent
|
|
56
|
-
aip init # Initialize configuration
|
|
55
|
+
aip agents run my-agent "Hello world" # Run an agent
|
|
57
56
|
"""
|
|
58
57
|
|
|
59
58
|
# Store configuration in context
|
|
@@ -72,7 +71,6 @@ main.add_command(config_group)
|
|
|
72
71
|
main.add_command(tools_group)
|
|
73
72
|
main.add_command(mcps_group)
|
|
74
73
|
main.add_command(models_group)
|
|
75
|
-
main.add_command(init_command)
|
|
76
74
|
|
|
77
75
|
# Add top-level commands
|
|
78
76
|
main.add_command(configure_command)
|
|
@@ -89,6 +87,12 @@ def status(ctx):
|
|
|
89
87
|
try:
|
|
90
88
|
console = Console()
|
|
91
89
|
|
|
90
|
+
# Display AIP status banner
|
|
91
|
+
branding = AIPBranding.create_from_sdk(
|
|
92
|
+
sdk_version=_SDK_VERSION, package_name="glaip-sdk"
|
|
93
|
+
)
|
|
94
|
+
branding.display_status_banner("ready")
|
|
95
|
+
|
|
92
96
|
# Load config from file and merge with context
|
|
93
97
|
file_config = load_config()
|
|
94
98
|
context_config = ctx.obj or {}
|
|
@@ -109,7 +113,7 @@ def status(ctx):
|
|
|
109
113
|
|
|
110
114
|
if not config.get("api_url") or not config.get("api_key"):
|
|
111
115
|
console.print(
|
|
112
|
-
|
|
116
|
+
AIPPanel(
|
|
113
117
|
"[bold red]❌ Configuration incomplete[/bold red]\n\n"
|
|
114
118
|
f"🔍 Current config:\n"
|
|
115
119
|
f" • API URL: {config.get('api_url', 'Not set')}\n"
|
|
@@ -137,7 +141,7 @@ def status(ctx):
|
|
|
137
141
|
mcps = client.list_mcps()
|
|
138
142
|
|
|
139
143
|
# Create status table
|
|
140
|
-
table =
|
|
144
|
+
table = AIPTable(title="🔗 GL AIP Status")
|
|
141
145
|
table.add_column("Resource", style="cyan", width=15)
|
|
142
146
|
table.add_column("Count", style="green", width=10)
|
|
143
147
|
table.add_column("Status", style="green", width=15)
|
|
@@ -147,8 +151,8 @@ def status(ctx):
|
|
|
147
151
|
table.add_row("MCPs", str(len(mcps)), "✅ Available")
|
|
148
152
|
|
|
149
153
|
console.print(
|
|
150
|
-
|
|
151
|
-
f"[bold green]✅ Connected to AIP
|
|
154
|
+
AIPPanel(
|
|
155
|
+
f"[bold green]✅ Connected to GL AIP[/bold green]\n"
|
|
152
156
|
f"🔗 API URL: {client.api_url}\n"
|
|
153
157
|
f"🤖 Agent Run Timeout: {DEFAULT_AGENT_RUN_TIMEOUT}s",
|
|
154
158
|
title="🚀 Connection Status",
|
|
@@ -160,7 +164,7 @@ def status(ctx):
|
|
|
160
164
|
|
|
161
165
|
except Exception as e:
|
|
162
166
|
console.print(
|
|
163
|
-
|
|
167
|
+
AIPPanel(
|
|
164
168
|
f"[bold yellow]⚠️ Connection established but API call failed[/bold yellow]\n"
|
|
165
169
|
f"🔗 API URL: {client.api_url}\n"
|
|
166
170
|
f"❌ Error: {e}\n\n"
|
|
@@ -177,7 +181,7 @@ def status(ctx):
|
|
|
177
181
|
|
|
178
182
|
except Exception as e:
|
|
179
183
|
console.print(
|
|
180
|
-
|
|
184
|
+
AIPPanel(
|
|
181
185
|
f"[bold red]❌ Connection failed[/bold red]\n\n"
|
|
182
186
|
f"🔍 Error: {e}\n\n"
|
|
183
187
|
f"💡 Troubleshooting steps:\n"
|
|
@@ -195,7 +199,10 @@ def status(ctx):
|
|
|
195
199
|
@main.command()
|
|
196
200
|
def version():
|
|
197
201
|
"""Show version information."""
|
|
198
|
-
|
|
202
|
+
branding = AIPBranding.create_from_sdk(
|
|
203
|
+
sdk_version=_SDK_VERSION, package_name="glaip-sdk"
|
|
204
|
+
)
|
|
205
|
+
branding.display_version_panel()
|
|
199
206
|
|
|
200
207
|
|
|
201
208
|
@main.command()
|
|
@@ -214,7 +221,7 @@ def update(check_only: bool, force: bool):
|
|
|
214
221
|
|
|
215
222
|
if check_only:
|
|
216
223
|
console.print(
|
|
217
|
-
|
|
224
|
+
AIPPanel(
|
|
218
225
|
"[bold blue]🔍 Checking for updates...[/bold blue]\n\n"
|
|
219
226
|
"💡 To install updates, run: aip update",
|
|
220
227
|
title="📋 Update Check",
|
|
@@ -224,7 +231,7 @@ def update(check_only: bool, force: bool):
|
|
|
224
231
|
return
|
|
225
232
|
|
|
226
233
|
console.print(
|
|
227
|
-
|
|
234
|
+
AIPPanel(
|
|
228
235
|
"[bold blue]🔄 Updating AIP SDK...[/bold blue]\n\n"
|
|
229
236
|
"📦 This will update the package from PyPI\n"
|
|
230
237
|
"💡 Use --check-only to just check for updates",
|
|
@@ -249,7 +256,7 @@ def update(check_only: bool, force: bool):
|
|
|
249
256
|
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
250
257
|
|
|
251
258
|
console.print(
|
|
252
|
-
|
|
259
|
+
AIPPanel(
|
|
253
260
|
"[bold green]✅ Update successful![/bold green]\n\n"
|
|
254
261
|
"🔄 AIP SDK has been updated to the latest version\n"
|
|
255
262
|
"💡 Restart your terminal or run 'aip --version' to verify",
|
|
@@ -270,7 +277,7 @@ def update(check_only: bool, force: bool):
|
|
|
270
277
|
|
|
271
278
|
except subprocess.CalledProcessError as e:
|
|
272
279
|
console.print(
|
|
273
|
-
|
|
280
|
+
AIPPanel(
|
|
274
281
|
f"[bold red]❌ Update failed[/bold red]\n\n"
|
|
275
282
|
f"🔍 Error: {e.stderr}\n\n"
|
|
276
283
|
"💡 Troubleshooting:\n"
|
|
@@ -286,7 +293,7 @@ def update(check_only: bool, force: bool):
|
|
|
286
293
|
|
|
287
294
|
except ImportError:
|
|
288
295
|
console.print(
|
|
289
|
-
|
|
296
|
+
AIPPanel(
|
|
290
297
|
"[bold red]❌ Rich library not available[/bold red]\n\n"
|
|
291
298
|
"💡 Install rich: pip install rich\n"
|
|
292
299
|
" Then try: aip update",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""CLI resource resolution utilities for handling ID/name references.
|
|
2
|
+
|
|
3
|
+
This module provides CLI-specific resource resolution functionality,
|
|
4
|
+
including interactive pickers and ambiguity handling.
|
|
5
|
+
|
|
6
|
+
Authors:
|
|
7
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
|
|
12
|
+
import click
|
|
13
|
+
|
|
14
|
+
from glaip_sdk.cli.utils import resolve_resource
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def resolve_resource_reference(
|
|
18
|
+
ctx,
|
|
19
|
+
_client,
|
|
20
|
+
reference: str,
|
|
21
|
+
resource_type: str,
|
|
22
|
+
get_by_id_func: Callable,
|
|
23
|
+
find_by_name_func: Callable,
|
|
24
|
+
label: str,
|
|
25
|
+
select: int = None,
|
|
26
|
+
interface_preference: str | None = None,
|
|
27
|
+
):
|
|
28
|
+
"""Resolve resource reference (ID or name) with ambiguity handling.
|
|
29
|
+
|
|
30
|
+
This is a common pattern used across all resource types.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
ctx: Click context
|
|
34
|
+
client: API client
|
|
35
|
+
reference: Resource ID or name
|
|
36
|
+
resource_type: Type of resource
|
|
37
|
+
get_by_id_func: Function to get resource by ID
|
|
38
|
+
find_by_name_func: Function to find resources by name
|
|
39
|
+
label: Label for error messages
|
|
40
|
+
select: Selection index for ambiguous matches
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Resolved resource object
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
click.ClickException: If resolution fails
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
return resolve_resource(
|
|
50
|
+
ctx,
|
|
51
|
+
reference,
|
|
52
|
+
get_by_id=get_by_id_func,
|
|
53
|
+
find_by_name=find_by_name_func,
|
|
54
|
+
label=label,
|
|
55
|
+
select=select,
|
|
56
|
+
interface_preference=interface_preference,
|
|
57
|
+
)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise click.ClickException(f"Failed to resolve {resource_type.lower()}: {e}")
|