glaip-sdk 0.0.16__py3-none-any.whl → 0.0.18__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 +1 -1
- glaip_sdk/branding.py +1 -1
- glaip_sdk/cli/commands/agents.py +10 -10
- glaip_sdk/cli/commands/configure.py +7 -2
- glaip_sdk/cli/commands/mcps.py +18 -19
- glaip_sdk/cli/commands/tools.py +19 -13
- glaip_sdk/cli/display.py +5 -4
- glaip_sdk/cli/rich_helpers.py +29 -0
- glaip_sdk/cli/slash/prompt.py +32 -17
- glaip_sdk/cli/slash/session.py +54 -25
- glaip_sdk/cli/utils.py +6 -6
- glaip_sdk/client/agents.py +581 -88
- glaip_sdk/client/main.py +10 -2
- glaip_sdk/client/tools.py +34 -3
- glaip_sdk/config/constants.py +1 -1
- glaip_sdk/utils/agent_config.py +49 -26
- glaip_sdk/utils/rendering/formatting.py +50 -29
- glaip_sdk/utils/rendering/renderer/base.py +156 -70
- {glaip_sdk-0.0.16.dist-info → glaip_sdk-0.0.18.dist-info}/METADATA +2 -2
- {glaip_sdk-0.0.16.dist-info → glaip_sdk-0.0.18.dist-info}/RECORD +22 -21
- {glaip_sdk-0.0.16.dist-info → glaip_sdk-0.0.18.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.16.dist-info → glaip_sdk-0.0.18.dist-info}/entry_points.txt +0 -0
glaip_sdk/__init__.py
CHANGED
glaip_sdk/branding.py
CHANGED
|
@@ -42,7 +42,7 @@ LABEL = "bold"
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class AIPBranding:
|
|
45
|
-
"""GL AIP
|
|
45
|
+
"""GL AIP branding utilities with ASCII banner and version display."""
|
|
46
46
|
|
|
47
47
|
# GL AIP ASCII art - Modern block style with enhanced visibility
|
|
48
48
|
AIP_LOGO = r"""
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -12,7 +12,6 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
import click
|
|
14
14
|
from rich.console import Console
|
|
15
|
-
from rich.text import Text
|
|
16
15
|
|
|
17
16
|
from glaip_sdk.cli.agent_config import (
|
|
18
17
|
merge_agent_config_with_cli_args as merge_import_with_cli_args,
|
|
@@ -45,6 +44,7 @@ from glaip_sdk.cli.io import (
|
|
|
45
44
|
load_resource_from_file_with_validation as load_resource_from_file,
|
|
46
45
|
)
|
|
47
46
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
47
|
+
from glaip_sdk.cli.rich_helpers import markup_text, print_markup
|
|
48
48
|
from glaip_sdk.cli.utils import (
|
|
49
49
|
_fuzzy_pick_for_resources,
|
|
50
50
|
build_renderer,
|
|
@@ -275,7 +275,7 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
|
|
|
275
275
|
def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
276
276
|
"""Display full agent details using raw API data to preserve ALL fields."""
|
|
277
277
|
if agent is None:
|
|
278
|
-
handle_rich_output(ctx,
|
|
278
|
+
handle_rich_output(ctx, markup_text("[red]❌ No agent provided[/red]"))
|
|
279
279
|
return
|
|
280
280
|
|
|
281
281
|
# Try to fetch and format raw agent data first
|
|
@@ -297,7 +297,8 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
297
297
|
else:
|
|
298
298
|
# Fall back to Pydantic model data if raw fetch fails
|
|
299
299
|
handle_rich_output(
|
|
300
|
-
ctx,
|
|
300
|
+
ctx,
|
|
301
|
+
markup_text("[yellow]Falling back to Pydantic model data[/yellow]"),
|
|
301
302
|
)
|
|
302
303
|
|
|
303
304
|
with spinner_context(
|
|
@@ -495,18 +496,19 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
|
|
|
495
496
|
except Exception as e:
|
|
496
497
|
handle_rich_output(
|
|
497
498
|
ctx,
|
|
498
|
-
|
|
499
|
+
markup_text(
|
|
499
500
|
f"[yellow]⚠️ Could not fetch full agent details: {e}[/yellow]"
|
|
500
501
|
),
|
|
501
502
|
)
|
|
502
503
|
handle_rich_output(
|
|
503
|
-
ctx,
|
|
504
|
+
ctx,
|
|
505
|
+
markup_text("[yellow]⚠️ Proceeding with available data[/yellow]"),
|
|
504
506
|
)
|
|
505
507
|
|
|
506
508
|
export_resource_to_file(agent, export_path, detected_format)
|
|
507
509
|
handle_rich_output(
|
|
508
510
|
ctx,
|
|
509
|
-
|
|
511
|
+
markup_text(
|
|
510
512
|
f"[green]✅ Complete agent configuration exported to: {export_path} (format: {detected_format})[/green]"
|
|
511
513
|
),
|
|
512
514
|
)
|
|
@@ -619,7 +621,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
|
|
|
619
621
|
|
|
620
622
|
with open(save, "w", encoding="utf-8") as f:
|
|
621
623
|
f.write(content)
|
|
622
|
-
|
|
624
|
+
print_markup(f"[green]Full debug output saved to: {save}[/green]", console=console)
|
|
623
625
|
|
|
624
626
|
|
|
625
627
|
@agents_group.command()
|
|
@@ -1306,8 +1308,6 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1306
1308
|
|
|
1307
1309
|
# Show success message for non-JSON output
|
|
1308
1310
|
if get_ctx_value(ctx, "view") != "json":
|
|
1309
|
-
from rich.text import Text
|
|
1310
|
-
|
|
1311
1311
|
# Extract some useful info from the result
|
|
1312
1312
|
success_count = result.get("data", {}).get("created_count", 0) + result.get(
|
|
1313
1313
|
"data", {}
|
|
@@ -1316,7 +1316,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1316
1316
|
|
|
1317
1317
|
handle_rich_output(
|
|
1318
1318
|
ctx,
|
|
1319
|
-
|
|
1319
|
+
markup_text(
|
|
1320
1320
|
f"[green]✅ Successfully synced {success_count} LangFlow agents ({total_count} total processed)[/green]"
|
|
1321
1321
|
),
|
|
1322
1322
|
)
|
|
@@ -14,6 +14,7 @@ from glaip_sdk import Client
|
|
|
14
14
|
from glaip_sdk._version import __version__ as _SDK_VERSION
|
|
15
15
|
from glaip_sdk.branding import AIPBranding
|
|
16
16
|
from glaip_sdk.cli.config import CONFIG_FILE, load_config, save_config
|
|
17
|
+
from glaip_sdk.cli.rich_helpers import markup_text
|
|
17
18
|
from glaip_sdk.cli.utils import command_hint
|
|
18
19
|
from glaip_sdk.rich_components import AIPTable
|
|
19
20
|
|
|
@@ -88,7 +89,9 @@ def get_config(key: str) -> None:
|
|
|
88
89
|
config = load_config()
|
|
89
90
|
|
|
90
91
|
if key not in config:
|
|
91
|
-
console.print(
|
|
92
|
+
console.print(
|
|
93
|
+
markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
|
|
94
|
+
)
|
|
92
95
|
raise click.ClickException(f"Configuration key not found: {key}")
|
|
93
96
|
|
|
94
97
|
value = config[key]
|
|
@@ -108,7 +111,9 @@ def unset_config(key: str) -> None:
|
|
|
108
111
|
config = load_config()
|
|
109
112
|
|
|
110
113
|
if key not in config:
|
|
111
|
-
console.print(
|
|
114
|
+
console.print(
|
|
115
|
+
markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
|
|
116
|
+
)
|
|
112
117
|
return
|
|
113
118
|
|
|
114
119
|
del config[key]
|
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -11,7 +11,6 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
import click
|
|
13
13
|
from rich.console import Console
|
|
14
|
-
from rich.text import Text
|
|
15
14
|
|
|
16
15
|
from glaip_sdk.cli.context import detect_export_format, get_ctx_value, output_flags
|
|
17
16
|
from glaip_sdk.cli.display import (
|
|
@@ -33,6 +32,7 @@ from glaip_sdk.cli.mcp_validators import (
|
|
|
33
32
|
)
|
|
34
33
|
from glaip_sdk.cli.parsers.json_input import parse_json_input
|
|
35
34
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
35
|
+
from glaip_sdk.cli.rich_helpers import print_markup
|
|
36
36
|
from glaip_sdk.cli.utils import (
|
|
37
37
|
coerce_to_row,
|
|
38
38
|
get_client,
|
|
@@ -481,21 +481,23 @@ def _handle_mcp_export(
|
|
|
481
481
|
):
|
|
482
482
|
mcp = client.mcps.get_mcp_by_id(mcp.id)
|
|
483
483
|
except Exception as e:
|
|
484
|
-
|
|
485
|
-
|
|
484
|
+
print_markup(
|
|
485
|
+
f"[yellow]⚠️ Could not fetch full MCP details: {e}[/yellow]",
|
|
486
|
+
console=console,
|
|
487
|
+
)
|
|
488
|
+
print_markup(
|
|
489
|
+
"[yellow]⚠️ Proceeding with available data[/yellow]", console=console
|
|
486
490
|
)
|
|
487
|
-
console.print(Text("[yellow]⚠️ Proceeding with available data[/yellow]"))
|
|
488
491
|
|
|
489
492
|
# Determine if we should prompt for secrets
|
|
490
493
|
prompt_for_secrets = not no_auth_prompt and sys.stdin.isatty()
|
|
491
494
|
|
|
492
495
|
# Warn user if non-interactive mode forces placeholder usage
|
|
493
496
|
if not no_auth_prompt and not sys.stdin.isatty():
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
)
|
|
497
|
+
print_markup(
|
|
498
|
+
"[yellow]⚠️ Non-interactive mode detected. "
|
|
499
|
+
"Using placeholder values for secrets.[/yellow]",
|
|
500
|
+
console=console,
|
|
499
501
|
)
|
|
500
502
|
|
|
501
503
|
# Build and write export payload
|
|
@@ -528,11 +530,10 @@ def _handle_mcp_export(
|
|
|
528
530
|
)
|
|
529
531
|
write_resource_export(export_path, export_payload, detected_format)
|
|
530
532
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
)
|
|
533
|
+
print_markup(
|
|
534
|
+
f"[green]✅ Complete MCP configuration exported to: "
|
|
535
|
+
f"{export_path} (format: {detected_format})[/green]",
|
|
536
|
+
console=console,
|
|
536
537
|
)
|
|
537
538
|
|
|
538
539
|
|
|
@@ -732,11 +733,9 @@ def connect(ctx: Any, config_file: str) -> None:
|
|
|
732
733
|
|
|
733
734
|
view = get_ctx_value(ctx, "view", "rich")
|
|
734
735
|
if view != "json":
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
f"{config_file}...[/yellow]"
|
|
739
|
-
)
|
|
736
|
+
print_markup(
|
|
737
|
+
f"[yellow]Connecting to MCP with config from {config_file}...[/yellow]",
|
|
738
|
+
console=console,
|
|
740
739
|
)
|
|
741
740
|
|
|
742
741
|
# Test connection using config
|
glaip_sdk/cli/commands/tools.py
CHANGED
|
@@ -11,7 +11,6 @@ from typing import Any
|
|
|
11
11
|
|
|
12
12
|
import click
|
|
13
13
|
from rich.console import Console
|
|
14
|
-
from rich.text import Text
|
|
15
14
|
|
|
16
15
|
from glaip_sdk.cli.context import detect_export_format, get_ctx_value, output_flags
|
|
17
16
|
from glaip_sdk.cli.display import (
|
|
@@ -33,6 +32,7 @@ from glaip_sdk.cli.io import (
|
|
|
33
32
|
load_resource_from_file_with_validation as load_resource_from_file,
|
|
34
33
|
)
|
|
35
34
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
35
|
+
from glaip_sdk.cli.rich_helpers import markup_text, print_markup
|
|
36
36
|
from glaip_sdk.cli.utils import (
|
|
37
37
|
coerce_to_row,
|
|
38
38
|
get_client,
|
|
@@ -349,11 +349,13 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
349
349
|
):
|
|
350
350
|
tool = client.get_tool_by_id(tool.id)
|
|
351
351
|
except Exception as e:
|
|
352
|
-
|
|
353
|
-
|
|
352
|
+
print_markup(
|
|
353
|
+
f"[yellow]⚠️ Could not fetch full tool details: {e}[/yellow]",
|
|
354
|
+
console=console,
|
|
354
355
|
)
|
|
355
|
-
|
|
356
|
-
|
|
356
|
+
print_markup(
|
|
357
|
+
"[yellow]⚠️ Proceeding with available data[/yellow]",
|
|
358
|
+
console=console,
|
|
357
359
|
)
|
|
358
360
|
|
|
359
361
|
with spinner_context(
|
|
@@ -362,10 +364,9 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
362
364
|
console_override=console,
|
|
363
365
|
):
|
|
364
366
|
export_resource_to_file(tool, export_path, detected_format)
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
)
|
|
367
|
+
print_markup(
|
|
368
|
+
f"[green]✅ Complete tool configuration exported to: {export_path} (format: {detected_format})[/green]",
|
|
369
|
+
console=console,
|
|
369
370
|
)
|
|
370
371
|
|
|
371
372
|
# Try to fetch raw API data first to preserve ALL fields
|
|
@@ -473,7 +474,8 @@ def update(
|
|
|
473
474
|
tool.id, file, framework=tool.framework
|
|
474
475
|
)
|
|
475
476
|
handle_rich_output(
|
|
476
|
-
ctx,
|
|
477
|
+
ctx,
|
|
478
|
+
markup_text(f"[green]✓[/green] Tool code updated from {file}"),
|
|
477
479
|
)
|
|
478
480
|
elif update_data:
|
|
479
481
|
# Update metadata only (native tools only)
|
|
@@ -487,9 +489,13 @@ def update(
|
|
|
487
489
|
console_override=console,
|
|
488
490
|
):
|
|
489
491
|
updated_tool = tool.update(**update_data)
|
|
490
|
-
handle_rich_output(
|
|
492
|
+
handle_rich_output(
|
|
493
|
+
ctx, markup_text("[green]✓[/green] Tool metadata updated")
|
|
494
|
+
)
|
|
491
495
|
else:
|
|
492
|
-
handle_rich_output(
|
|
496
|
+
handle_rich_output(
|
|
497
|
+
ctx, markup_text("[yellow]No updates specified[/yellow]")
|
|
498
|
+
)
|
|
493
499
|
return
|
|
494
500
|
|
|
495
501
|
handle_json_output(ctx, updated_tool.model_dump())
|
|
@@ -574,5 +580,5 @@ def script(ctx: Any, tool_id: str) -> None:
|
|
|
574
580
|
except Exception as e:
|
|
575
581
|
handle_json_output(ctx, error=e)
|
|
576
582
|
if get_ctx_value(ctx, "view") != "json":
|
|
577
|
-
|
|
583
|
+
print_markup(f"[red]Error getting tool script: {e}[/red]", console=console)
|
|
578
584
|
raise click.ClickException(str(e))
|
glaip_sdk/cli/display.py
CHANGED
|
@@ -15,6 +15,7 @@ from rich.console import Console
|
|
|
15
15
|
from rich.panel import Panel
|
|
16
16
|
from rich.text import Text
|
|
17
17
|
|
|
18
|
+
from glaip_sdk.cli.rich_helpers import markup_text, print_markup
|
|
18
19
|
from glaip_sdk.cli.utils import command_hint
|
|
19
20
|
from glaip_sdk.rich_components import AIPPanel
|
|
20
21
|
|
|
@@ -61,7 +62,7 @@ def display_update_success(resource_type: str, resource_name: str) -> Text:
|
|
|
61
62
|
Returns:
|
|
62
63
|
Rich Text object for display
|
|
63
64
|
"""
|
|
64
|
-
return
|
|
65
|
+
return markup_text(
|
|
65
66
|
f"[green]✅ {resource_type} '{resource_name}' updated successfully[/green]"
|
|
66
67
|
)
|
|
67
68
|
|
|
@@ -76,7 +77,7 @@ def display_deletion_success(resource_type: str, resource_name: str) -> Text:
|
|
|
76
77
|
Returns:
|
|
77
78
|
Rich Text object for display
|
|
78
79
|
"""
|
|
79
|
-
return
|
|
80
|
+
return markup_text(
|
|
80
81
|
f"[green]✅ {resource_type} '{resource_name}' deleted successfully[/green]"
|
|
81
82
|
)
|
|
82
83
|
|
|
@@ -89,8 +90,8 @@ def display_api_error(error: Exception, operation: str = "operation") -> None:
|
|
|
89
90
|
operation: Description of the operation that failed
|
|
90
91
|
"""
|
|
91
92
|
error_type = type(error).__name__
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
print_markup(f"[red]Error during {operation}: {error}[/red]", console=console)
|
|
94
|
+
print_markup(f"[dim]Error type: {error_type}[/dim]", console=console)
|
|
94
95
|
|
|
95
96
|
|
|
96
97
|
def print_api_error(e: Exception) -> None:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Shared helpers for creating and printing Rich markup content.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.markup import MarkupError
|
|
13
|
+
from rich.text import Text
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def markup_text(message: str, **kwargs: Any) -> Text:
|
|
17
|
+
"""Create a Rich Text instance from markup with graceful fallback."""
|
|
18
|
+
try:
|
|
19
|
+
return Text.from_markup(message, **kwargs)
|
|
20
|
+
except MarkupError:
|
|
21
|
+
return Text(message, **kwargs)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def print_markup(
|
|
25
|
+
message: str, *, console: Console | None = None, **kwargs: Any
|
|
26
|
+
) -> None:
|
|
27
|
+
"""Print markup-aware text to the provided console (default: new Console)."""
|
|
28
|
+
target_console = console or Console()
|
|
29
|
+
target_console.print(markup_text(message, **kwargs))
|
glaip_sdk/cli/slash/prompt.py
CHANGED
|
@@ -194,28 +194,43 @@ def _iter_command_completions(
|
|
|
194
194
|
prefix = text[1:]
|
|
195
195
|
seen: set[str] = set()
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
and not session.should_include_global_commands()
|
|
200
|
-
):
|
|
197
|
+
# Early return for contextual commands scenario
|
|
198
|
+
if not _should_include_commands(session):
|
|
201
199
|
return []
|
|
202
200
|
|
|
203
201
|
commands = sorted(session._unique_commands.values(), key=lambda c: c.name)
|
|
204
202
|
|
|
205
203
|
for cmd in commands:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
204
|
+
yield from _generate_command_completions(cmd, prefix, text, seen)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _should_include_commands(session: SlashSession) -> bool:
|
|
208
|
+
"""Check if commands should be included in completions."""
|
|
209
|
+
return not (
|
|
210
|
+
session.get_contextual_commands()
|
|
211
|
+
and not session.should_include_global_commands()
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _generate_command_completions(
|
|
216
|
+
cmd: Any, prefix: str, text: str, seen: set[str]
|
|
217
|
+
) -> Iterable[Completion]:
|
|
218
|
+
"""Generate completion items for a single command."""
|
|
219
|
+
for alias in (cmd.name, *cmd.aliases):
|
|
220
|
+
if alias in seen or alias.startswith("?"):
|
|
221
|
+
continue
|
|
222
|
+
|
|
223
|
+
if prefix and not alias.startswith(prefix):
|
|
224
|
+
continue
|
|
225
|
+
|
|
226
|
+
seen.add(alias)
|
|
227
|
+
label = f"/{alias}"
|
|
228
|
+
yield Completion(
|
|
229
|
+
text=label,
|
|
230
|
+
start_position=-len(text),
|
|
231
|
+
display=label,
|
|
232
|
+
display_meta=cmd.help,
|
|
233
|
+
)
|
|
219
234
|
|
|
220
235
|
|
|
221
236
|
def _iter_contextual_completions(
|
glaip_sdk/cli/slash/session.py
CHANGED
|
@@ -297,51 +297,80 @@ class SlashSession:
|
|
|
297
297
|
return True
|
|
298
298
|
|
|
299
299
|
def _cmd_agents(self, args: list[str], _invoked_from_agent: bool) -> bool:
|
|
300
|
+
client = self._get_client_or_fail()
|
|
301
|
+
if not client:
|
|
302
|
+
return True
|
|
303
|
+
|
|
304
|
+
agents = self._get_agents_or_fail(client)
|
|
305
|
+
if not agents:
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
picked_agent = self._resolve_or_pick_agent(client, agents, args)
|
|
309
|
+
|
|
310
|
+
if not picked_agent:
|
|
311
|
+
return True
|
|
312
|
+
|
|
313
|
+
return self._run_agent_session(picked_agent)
|
|
314
|
+
|
|
315
|
+
def _get_client_or_fail(self) -> Any:
|
|
316
|
+
"""Get client or handle failure and return None."""
|
|
300
317
|
try:
|
|
301
|
-
|
|
318
|
+
return self._get_client()
|
|
302
319
|
except click.ClickException as exc:
|
|
303
320
|
self.console.print(f"[red]{exc}[/red]")
|
|
304
|
-
return
|
|
321
|
+
return None
|
|
305
322
|
|
|
323
|
+
def _get_agents_or_fail(self, client: Any) -> list:
|
|
324
|
+
"""Get agents list or handle failure and return empty list."""
|
|
306
325
|
try:
|
|
307
326
|
agents = client.list_agents()
|
|
327
|
+
if not agents:
|
|
328
|
+
self._handle_no_agents()
|
|
329
|
+
return agents
|
|
308
330
|
except Exception as exc: # pragma: no cover - API failures
|
|
309
331
|
self.console.print(f"[red]Failed to load agents: {exc}[/red]")
|
|
310
|
-
return
|
|
332
|
+
return []
|
|
311
333
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
334
|
+
def _handle_no_agents(self) -> None:
|
|
335
|
+
"""Handle case when no agents are available."""
|
|
336
|
+
hint = command_hint("agents create", slash_command=None, ctx=self.ctx)
|
|
337
|
+
if hint:
|
|
338
|
+
self.console.print(
|
|
339
|
+
f"[yellow]No agents available. Use `{hint}` to add one.[/yellow]"
|
|
340
|
+
)
|
|
341
|
+
else:
|
|
342
|
+
self.console.print("[yellow]No agents available.[/yellow]")
|
|
321
343
|
|
|
344
|
+
def _resolve_or_pick_agent(self, client: Any, agents: list, args: list[str]) -> Any:
|
|
345
|
+
"""Resolve agent from args or pick interactively."""
|
|
322
346
|
if args:
|
|
323
347
|
picked_agent = self._resolve_agent_from_ref(client, agents, args[0])
|
|
324
348
|
if picked_agent is None:
|
|
325
349
|
self.console.print(
|
|
326
350
|
f"[yellow]Could not resolve agent '{args[0]}'. Try `/agents` to browse interactively.[/yellow]"
|
|
327
351
|
)
|
|
328
|
-
return
|
|
352
|
+
return None
|
|
329
353
|
else:
|
|
330
354
|
picked_agent = _fuzzy_pick_for_resources(agents, "agent", "")
|
|
331
355
|
|
|
332
|
-
|
|
333
|
-
return True
|
|
356
|
+
return picked_agent
|
|
334
357
|
|
|
358
|
+
def _run_agent_session(self, picked_agent: Any) -> bool:
|
|
359
|
+
"""Run agent session and show follow-up actions."""
|
|
335
360
|
self._remember_agent(picked_agent)
|
|
336
|
-
|
|
337
361
|
AgentRunSession(self, picked_agent).run()
|
|
338
362
|
|
|
339
|
-
# Refresh the main palette header and surface follow-up actions
|
|
340
|
-
# user has immediate cues after leaving the agent context.
|
|
363
|
+
# Refresh the main palette header and surface follow-up actions
|
|
341
364
|
self._render_header()
|
|
342
365
|
|
|
366
|
+
self._show_agent_followup_actions(picked_agent)
|
|
367
|
+
return True
|
|
368
|
+
|
|
369
|
+
def _show_agent_followup_actions(self, picked_agent: Any) -> None:
|
|
370
|
+
"""Show follow-up action hints after agent session."""
|
|
343
371
|
agent_id = str(getattr(picked_agent, "id", ""))
|
|
344
372
|
agent_label = getattr(picked_agent, "name", "") or agent_id or "this agent"
|
|
373
|
+
|
|
345
374
|
hints: list[tuple[str, str]] = []
|
|
346
375
|
if agent_id:
|
|
347
376
|
hints.append((f"/agents {agent_id}", f"Reopen {agent_label}"))
|
|
@@ -351,8 +380,8 @@ class SlashSession:
|
|
|
351
380
|
(self.STATUS_COMMAND, "Check connection"),
|
|
352
381
|
]
|
|
353
382
|
)
|
|
383
|
+
|
|
354
384
|
self._show_quick_actions(hints, title="Next actions")
|
|
355
|
-
return True
|
|
356
385
|
|
|
357
386
|
def _cmd_exit(self, _args: list[str], invoked_from_agent: bool) -> bool:
|
|
358
387
|
if invoked_from_agent:
|
|
@@ -710,12 +739,12 @@ class SlashSession:
|
|
|
710
739
|
|
|
711
740
|
if full:
|
|
712
741
|
lines = [
|
|
713
|
-
self._branding.
|
|
714
|
-
"",
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
742
|
+
f"GL AIP v{self._branding.version} · GDP Labs AI Agents Package",
|
|
743
|
+
f"API: {api_url or 'Not configured'} · Credentials: {status}",
|
|
744
|
+
(
|
|
745
|
+
f"Verbose: {'on' if self._verbose_enabled else 'off'} "
|
|
746
|
+
"(Ctrl+T toggles verbose streaming)"
|
|
747
|
+
),
|
|
719
748
|
]
|
|
720
749
|
extra: list[str] = []
|
|
721
750
|
self._add_agent_info_to_header(extra, active_agent)
|
glaip_sdk/cli/utils.py
CHANGED
|
@@ -19,8 +19,8 @@ import click
|
|
|
19
19
|
from rich.console import Console, Group
|
|
20
20
|
from rich.markdown import Markdown
|
|
21
21
|
from rich.pretty import Pretty
|
|
22
|
-
from rich.text import Text
|
|
23
22
|
|
|
23
|
+
from glaip_sdk.cli.rich_helpers import markup_text
|
|
24
24
|
from glaip_sdk.rich_components import AIPPanel
|
|
25
25
|
|
|
26
26
|
# Optional interactive deps (fuzzy palette)
|
|
@@ -557,7 +557,7 @@ def output_result(
|
|
|
557
557
|
if panel_title:
|
|
558
558
|
console.print(AIPPanel(renderable, title=panel_title))
|
|
559
559
|
else:
|
|
560
|
-
console.print(
|
|
560
|
+
console.print(markup_text(f"[cyan]{title}:[/cyan]"))
|
|
561
561
|
console.print(renderable)
|
|
562
562
|
|
|
563
563
|
|
|
@@ -635,7 +635,7 @@ def _build_table_group(
|
|
|
635
635
|
table = _create_table(columns, title)
|
|
636
636
|
for row in rows:
|
|
637
637
|
table.add_row(*[str(row.get(key, "N/A")) for key, _, _, _ in columns])
|
|
638
|
-
footer =
|
|
638
|
+
footer = markup_text(f"\n[dim]Total {len(rows)} items[/dim]")
|
|
639
639
|
return Group(table, footer)
|
|
640
640
|
|
|
641
641
|
|
|
@@ -665,7 +665,7 @@ def _handle_markdown_output(
|
|
|
665
665
|
|
|
666
666
|
def _handle_empty_items(title: str) -> None:
|
|
667
667
|
"""Handle case when no items are found."""
|
|
668
|
-
console.print(
|
|
668
|
+
console.print(markup_text(f"[yellow]No {title.lower()} found.[/yellow]"))
|
|
669
669
|
|
|
670
670
|
|
|
671
671
|
def _should_use_fuzzy_picker() -> bool:
|
|
@@ -707,7 +707,7 @@ def _print_selection_tip(title: str) -> None:
|
|
|
707
707
|
tip_cmd = _resource_tip_command(title)
|
|
708
708
|
if tip_cmd:
|
|
709
709
|
console.print(
|
|
710
|
-
|
|
710
|
+
markup_text(f"\n[dim]Tip: use `{tip_cmd} <ID>` for details[/dim]")
|
|
711
711
|
)
|
|
712
712
|
|
|
713
713
|
|
|
@@ -1092,7 +1092,7 @@ def _handle_fallback_numeric_ambiguity(
|
|
|
1092
1092
|
safe_ref = ref.replace("{", "{{").replace("}", "}}")
|
|
1093
1093
|
|
|
1094
1094
|
console.print(
|
|
1095
|
-
|
|
1095
|
+
markup_text(
|
|
1096
1096
|
f"[yellow]Multiple {safe_resource_type}s found matching '{safe_ref}':[/yellow]"
|
|
1097
1097
|
)
|
|
1098
1098
|
)
|