glaip-sdk 0.2.2__py3-none-any.whl → 0.4.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.
- glaip_sdk/cli/auth.py +2 -1
- glaip_sdk/cli/commands/agents.py +51 -36
- glaip_sdk/cli/commands/configure.py +2 -1
- glaip_sdk/cli/commands/mcps.py +219 -62
- glaip_sdk/cli/commands/models.py +3 -5
- glaip_sdk/cli/commands/tools.py +27 -16
- glaip_sdk/cli/commands/transcripts.py +1 -1
- glaip_sdk/cli/constants.py +3 -0
- glaip_sdk/cli/display.py +1 -1
- glaip_sdk/cli/hints.py +58 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +3 -4
- glaip_sdk/cli/slash/agent_session.py +4 -13
- glaip_sdk/cli/slash/prompt.py +3 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +139 -48
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +632 -0
- glaip_sdk/cli/transcript/capture.py +1 -1
- glaip_sdk/cli/transcript/viewer.py +19 -678
- glaip_sdk/cli/update_notifier.py +2 -1
- glaip_sdk/cli/utils.py +228 -101
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +40 -22
- glaip_sdk/client/main.py +2 -6
- glaip_sdk/client/mcps.py +13 -5
- glaip_sdk/client/run_rendering.py +90 -111
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +2 -3
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/models/__init__.py +56 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models.py +8 -7
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/utils/client_utils.py +13 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/import_export.py +6 -9
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +5 -30
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
- glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +1 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +10 -28
- glaip_sdk/utils/rendering/renderer/base.py +217 -1476
- glaip_sdk/utils/rendering/renderer/debug.py +24 -1
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -12
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -439
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +26 -15
- glaip_sdk/utils/validation.py +13 -21
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/METADATA +24 -2
- glaip_sdk-0.4.0.dist-info/RECORD +110 -0
- glaip_sdk-0.2.2.dist-info/RECORD +0 -87
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.2.2.dist-info → glaip_sdk-0.4.0.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/auth.py
CHANGED
|
@@ -18,7 +18,8 @@ import click
|
|
|
18
18
|
from rich.console import Console
|
|
19
19
|
|
|
20
20
|
from glaip_sdk.branding import HINT_PREFIX_STYLE, WARNING_STYLE
|
|
21
|
-
from glaip_sdk.cli.
|
|
21
|
+
from glaip_sdk.cli.hints import format_command_hint
|
|
22
|
+
from glaip_sdk.cli.utils import command_hint
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def prepare_authentication_export(
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -59,15 +59,17 @@ from glaip_sdk.cli.transcript import (
|
|
|
59
59
|
maybe_launch_post_run_viewer,
|
|
60
60
|
store_transcript_for_session,
|
|
61
61
|
)
|
|
62
|
+
from glaip_sdk.cli.hints import in_slash_mode
|
|
62
63
|
from glaip_sdk.cli.utils import (
|
|
63
64
|
_fuzzy_pick_for_resources,
|
|
64
65
|
build_renderer,
|
|
65
66
|
coerce_to_row,
|
|
66
67
|
get_client,
|
|
67
|
-
|
|
68
|
+
handle_resource_export,
|
|
68
69
|
output_list,
|
|
69
70
|
output_result,
|
|
70
71
|
spinner_context,
|
|
72
|
+
with_client_and_spinner,
|
|
71
73
|
)
|
|
72
74
|
from glaip_sdk.cli.validators import (
|
|
73
75
|
validate_agent_instruction_cli as validate_agent_instruction,
|
|
@@ -78,7 +80,7 @@ from glaip_sdk.cli.validators import (
|
|
|
78
80
|
from glaip_sdk.cli.validators import (
|
|
79
81
|
validate_timeout_cli as validate_timeout,
|
|
80
82
|
)
|
|
81
|
-
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT, DEFAULT_MODEL
|
|
83
|
+
from glaip_sdk.config.constants import AGENT_CONFIG_FIELDS, DEFAULT_AGENT_RUN_TIMEOUT, DEFAULT_MODEL
|
|
82
84
|
from glaip_sdk.exceptions import AgentTimeoutError
|
|
83
85
|
from glaip_sdk.icons import ICON_AGENT
|
|
84
86
|
from glaip_sdk.utils import format_datetime, is_uuid
|
|
@@ -146,10 +148,7 @@ def _build_fallback_agent_mapping(agent: Any) -> dict[str, Any]:
|
|
|
146
148
|
"description",
|
|
147
149
|
"model",
|
|
148
150
|
"agent_config",
|
|
149
|
-
"
|
|
150
|
-
"agents",
|
|
151
|
-
"mcps",
|
|
152
|
-
"timeout",
|
|
151
|
+
*[field for field in AGENT_CONFIG_FIELDS if field not in ("name", "instruction", "model")],
|
|
153
152
|
"tool_configs",
|
|
154
153
|
)
|
|
155
154
|
|
|
@@ -457,7 +456,6 @@ def agents_group() -> None:
|
|
|
457
456
|
pass
|
|
458
457
|
|
|
459
458
|
|
|
460
|
-
# pylint: disable=duplicate-code
|
|
461
459
|
def _resolve_agent(
|
|
462
460
|
ctx: Any,
|
|
463
461
|
client: Any,
|
|
@@ -465,26 +463,38 @@ def _resolve_agent(
|
|
|
465
463
|
select: int | None = None,
|
|
466
464
|
interface_preference: str = "fuzzy",
|
|
467
465
|
) -> Any | None:
|
|
468
|
-
"""Resolve agent
|
|
466
|
+
"""Resolve an agent by ID or name, supporting fuzzy and questionary interfaces.
|
|
467
|
+
|
|
468
|
+
This function provides agent-specific resolution with flexible UI options.
|
|
469
|
+
It wraps resolve_resource_reference with agent-specific configuration, allowing
|
|
470
|
+
users to choose between fuzzy search and traditional questionary selection.
|
|
469
471
|
|
|
470
472
|
Args:
|
|
471
|
-
ctx: Click context
|
|
472
|
-
client: AIP client instance
|
|
473
|
-
ref: Agent
|
|
474
|
-
select: Pre-selected
|
|
475
|
-
interface_preference: "fuzzy" for
|
|
473
|
+
ctx: Click context for CLI command execution.
|
|
474
|
+
client: AIP SDK client instance.
|
|
475
|
+
ref: Agent identifier (UUID or name string).
|
|
476
|
+
select: Pre-selected index for non-interactive resolution (1-based).
|
|
477
|
+
interface_preference: UI preference - "fuzzy" for search or "questionary" for list.
|
|
476
478
|
|
|
477
479
|
Returns:
|
|
478
|
-
|
|
480
|
+
Agent object when found, None when resolution fails.
|
|
479
481
|
"""
|
|
482
|
+
# Configure agent-specific resolution parameters
|
|
483
|
+
resolution_config = {
|
|
484
|
+
"resource_type": "agent",
|
|
485
|
+
"get_by_id": client.agents.get_agent_by_id,
|
|
486
|
+
"find_by_name": client.agents.find_agents,
|
|
487
|
+
"label": "Agent",
|
|
488
|
+
}
|
|
489
|
+
# Use agent-specific resolution with flexible interface preference
|
|
480
490
|
return resolve_resource_reference(
|
|
481
491
|
ctx,
|
|
482
492
|
client,
|
|
483
493
|
ref,
|
|
484
|
-
"
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
"
|
|
494
|
+
resolution_config["resource_type"],
|
|
495
|
+
resolution_config["get_by_id"],
|
|
496
|
+
resolution_config["find_by_name"],
|
|
497
|
+
resolution_config["label"],
|
|
488
498
|
select=select,
|
|
489
499
|
interface_preference=interface_preference,
|
|
490
500
|
)
|
|
@@ -514,19 +524,20 @@ def list_agents(
|
|
|
514
524
|
) -> None:
|
|
515
525
|
"""List agents with optional filtering."""
|
|
516
526
|
try:
|
|
517
|
-
|
|
518
|
-
with spinner_context(
|
|
527
|
+
with with_client_and_spinner(
|
|
519
528
|
ctx,
|
|
520
529
|
"[bold blue]Fetching agents…[/bold blue]",
|
|
521
530
|
console_override=console,
|
|
522
|
-
):
|
|
523
|
-
agents
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
531
|
+
) as client:
|
|
532
|
+
# Query agents with specified filters
|
|
533
|
+
filter_params = {
|
|
534
|
+
"agent_type": agent_type,
|
|
535
|
+
"framework": framework,
|
|
536
|
+
"name": name,
|
|
537
|
+
"version": version,
|
|
538
|
+
"sync_langflow_agents": sync_langflow,
|
|
539
|
+
}
|
|
540
|
+
agents = client.agents.list_agents(**filter_params)
|
|
530
541
|
|
|
531
542
|
# Define table columns: (data_key, header, style, width)
|
|
532
543
|
columns = [
|
|
@@ -621,28 +632,30 @@ def get(
|
|
|
621
632
|
aip agents get my-agent --export agent.yaml # Exports complete configuration as YAML
|
|
622
633
|
"""
|
|
623
634
|
try:
|
|
624
|
-
client
|
|
635
|
+
# Initialize API client for agent retrieval
|
|
636
|
+
api_client = get_client(ctx)
|
|
625
637
|
|
|
626
|
-
# Resolve agent
|
|
627
|
-
agent = _resolve_agent(ctx,
|
|
638
|
+
# Resolve agent reference using questionary interface for better UX
|
|
639
|
+
agent = _resolve_agent(ctx, api_client, agent_ref, select, interface_preference="questionary")
|
|
628
640
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
from glaip_sdk.cli.utils import handle_resource_export
|
|
641
|
+
if not agent:
|
|
642
|
+
raise click.ClickException(f"Agent '{agent_ref}' not found")
|
|
632
643
|
|
|
644
|
+
# Handle export option if requested
|
|
645
|
+
if export:
|
|
633
646
|
handle_resource_export(
|
|
634
647
|
ctx,
|
|
635
648
|
agent,
|
|
636
649
|
Path(export),
|
|
637
650
|
resource_type="agent",
|
|
638
|
-
get_by_id_func=
|
|
651
|
+
get_by_id_func=api_client.agents.get_agent_by_id,
|
|
639
652
|
console_override=console,
|
|
640
653
|
)
|
|
641
654
|
|
|
642
655
|
# Display full agent details using the standardized helper
|
|
643
656
|
_display_agent_details(
|
|
644
657
|
ctx,
|
|
645
|
-
|
|
658
|
+
api_client,
|
|
646
659
|
agent,
|
|
647
660
|
instruction_preview_limit=instruction_preview,
|
|
648
661
|
)
|
|
@@ -650,6 +663,8 @@ def get(
|
|
|
650
663
|
# Show run suggestions via centralized display helper
|
|
651
664
|
handle_rich_output(ctx, display_agent_run_suggestions(agent))
|
|
652
665
|
|
|
666
|
+
except click.ClickException:
|
|
667
|
+
raise
|
|
653
668
|
except Exception as e:
|
|
654
669
|
raise click.ClickException(str(e)) from e
|
|
655
670
|
|
|
@@ -23,7 +23,8 @@ from glaip_sdk.branding import (
|
|
|
23
23
|
)
|
|
24
24
|
from glaip_sdk.cli.config import CONFIG_FILE, load_config, save_config
|
|
25
25
|
from glaip_sdk.cli.rich_helpers import markup_text
|
|
26
|
-
from glaip_sdk.cli.
|
|
26
|
+
from glaip_sdk.cli.hints import format_command_hint
|
|
27
|
+
from glaip_sdk.cli.utils import command_hint, sdk_version
|
|
27
28
|
from glaip_sdk.icons import ICON_TOOL
|
|
28
29
|
from glaip_sdk.rich_components import AIPTable
|
|
29
30
|
|
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -43,10 +43,13 @@ from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
|
43
43
|
from glaip_sdk.cli.rich_helpers import print_markup
|
|
44
44
|
from glaip_sdk.cli.utils import (
|
|
45
45
|
coerce_to_row,
|
|
46
|
+
fetch_resource_for_export,
|
|
47
|
+
format_datetime_fields,
|
|
46
48
|
get_client,
|
|
47
49
|
output_list,
|
|
48
50
|
output_result,
|
|
49
51
|
spinner_context,
|
|
52
|
+
with_client_and_spinner,
|
|
50
53
|
)
|
|
51
54
|
from glaip_sdk.config.constants import (
|
|
52
55
|
DEFAULT_MCP_TYPE,
|
|
@@ -60,6 +63,7 @@ from glaip_sdk.utils.serialization import (
|
|
|
60
63
|
)
|
|
61
64
|
|
|
62
65
|
console = Console()
|
|
66
|
+
MAX_DESCRIPTION_LEN = 50
|
|
63
67
|
|
|
64
68
|
|
|
65
69
|
def _is_sensitive_data(val: Any) -> bool:
|
|
@@ -298,28 +302,37 @@ def mcps_group() -> None:
|
|
|
298
302
|
pass
|
|
299
303
|
|
|
300
304
|
|
|
301
|
-
def _resolve_mcp(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
302
|
-
"""Resolve MCP
|
|
305
|
+
def _resolve_mcp(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
306
|
+
"""Resolve an MCP server by ID or name, with interactive selection support.
|
|
307
|
+
|
|
308
|
+
This function provides MCP-specific resolution logic. It delegates to
|
|
309
|
+
resolve_resource_reference for MCP-specific resolution, supporting UUID
|
|
310
|
+
lookups and name-based fuzzy matching.
|
|
303
311
|
|
|
304
312
|
Args:
|
|
305
|
-
ctx: Click context
|
|
306
|
-
client: API client
|
|
307
|
-
ref: MCP
|
|
308
|
-
select:
|
|
313
|
+
ctx: Click context for command execution.
|
|
314
|
+
client: API client for backend operations.
|
|
315
|
+
ref: MCP identifier (UUID or name string).
|
|
316
|
+
select: Optional selection index when multiple MCPs match (1-based).
|
|
309
317
|
|
|
310
318
|
Returns:
|
|
311
|
-
MCP
|
|
319
|
+
MCP instance if resolution succeeds, None if not found.
|
|
312
320
|
|
|
313
321
|
Raises:
|
|
314
|
-
ClickException:
|
|
322
|
+
click.ClickException: When resolution fails or selection is invalid.
|
|
315
323
|
"""
|
|
324
|
+
# Configure MCP-specific resolution functions
|
|
325
|
+
mcp_client = client.mcps
|
|
326
|
+
get_by_id_func = mcp_client.get_mcp_by_id
|
|
327
|
+
find_by_name_func = mcp_client.find_mcps
|
|
328
|
+
# Use MCP-specific resolution with standard fuzzy matching
|
|
316
329
|
return resolve_resource_reference(
|
|
317
330
|
ctx,
|
|
318
331
|
client,
|
|
319
332
|
ref,
|
|
320
333
|
"mcp",
|
|
321
|
-
|
|
322
|
-
|
|
334
|
+
get_by_id_func,
|
|
335
|
+
find_by_name_func,
|
|
323
336
|
"MCP",
|
|
324
337
|
select=select,
|
|
325
338
|
)
|
|
@@ -512,12 +525,11 @@ def list_mcps(ctx: Any) -> None:
|
|
|
512
525
|
ClickException: If API request fails
|
|
513
526
|
"""
|
|
514
527
|
try:
|
|
515
|
-
|
|
516
|
-
with spinner_context(
|
|
528
|
+
with with_client_and_spinner(
|
|
517
529
|
ctx,
|
|
518
530
|
"[bold blue]Fetching MCPs…[/bold blue]",
|
|
519
531
|
console_override=console,
|
|
520
|
-
):
|
|
532
|
+
) as client:
|
|
521
533
|
mcps = client.mcps.list_mcps()
|
|
522
534
|
|
|
523
535
|
# Define table columns: (data_key, header, style, width)
|
|
@@ -612,8 +624,10 @@ def create(
|
|
|
612
624
|
aip mcps create --import mcp-export.json --name new-name --transport sse
|
|
613
625
|
"""
|
|
614
626
|
try:
|
|
615
|
-
client
|
|
627
|
+
# Get API client instance for MCP operations
|
|
628
|
+
api_client = get_client(ctx)
|
|
616
629
|
|
|
630
|
+
# Process import file if specified, otherwise use None
|
|
617
631
|
import_payload = _load_import_ready_payload(import_file) if import_file is not None else None
|
|
618
632
|
|
|
619
633
|
merged_payload, missing_fields = _merge_import_payload(
|
|
@@ -657,7 +671,7 @@ def create(
|
|
|
657
671
|
if mcp_metadata is not None:
|
|
658
672
|
create_kwargs["mcp_metadata"] = mcp_metadata
|
|
659
673
|
|
|
660
|
-
mcp =
|
|
674
|
+
mcp = api_client.mcps.create_mcp(**create_kwargs)
|
|
661
675
|
|
|
662
676
|
# Handle JSON output
|
|
663
677
|
handle_json_output(ctx, mcp.model_dump())
|
|
@@ -704,7 +718,6 @@ def _handle_mcp_export(
|
|
|
704
718
|
detected_format = detect_export_format(export_path)
|
|
705
719
|
|
|
706
720
|
# Always export comprehensive data - re-fetch with full details
|
|
707
|
-
from glaip_sdk.cli.utils import fetch_resource_for_export
|
|
708
721
|
|
|
709
722
|
mcp = fetch_resource_for_export(
|
|
710
723
|
ctx,
|
|
@@ -783,8 +796,6 @@ def _display_mcp_details(ctx: Any, client: Any, mcp: Any) -> None:
|
|
|
783
796
|
|
|
784
797
|
if raw_mcp_data:
|
|
785
798
|
# Use raw API data - this preserves ALL fields
|
|
786
|
-
from glaip_sdk.cli.utils import format_datetime_fields
|
|
787
|
-
|
|
788
799
|
formatted_data = format_datetime_fields(raw_mcp_data)
|
|
789
800
|
|
|
790
801
|
output_result(
|
|
@@ -869,64 +880,210 @@ def get(
|
|
|
869
880
|
raise click.ClickException(str(e)) from e
|
|
870
881
|
|
|
871
882
|
|
|
883
|
+
def _get_tools_from_config(ctx: Any, client: Any, config_file: str) -> tuple[list[dict[str, Any]], str]:
|
|
884
|
+
"""Get tools from MCP config file.
|
|
885
|
+
|
|
886
|
+
Args:
|
|
887
|
+
ctx: Click context
|
|
888
|
+
client: GlaIP client instance
|
|
889
|
+
config_file: Path to config file
|
|
890
|
+
|
|
891
|
+
Returns:
|
|
892
|
+
Tuple of (tools list, title string)
|
|
893
|
+
"""
|
|
894
|
+
config_data = load_resource_from_file_with_validation(Path(config_file), "MCP config")
|
|
895
|
+
|
|
896
|
+
# Validate config structure
|
|
897
|
+
transport = config_data.get("transport")
|
|
898
|
+
if "config" not in config_data:
|
|
899
|
+
raise click.ClickException("Invalid MCP config: missing 'config' section in the file.")
|
|
900
|
+
config_data["config"] = validate_mcp_config_structure(
|
|
901
|
+
config_data["config"],
|
|
902
|
+
transport=transport,
|
|
903
|
+
source=config_file,
|
|
904
|
+
)
|
|
905
|
+
|
|
906
|
+
# Get tools from config without saving
|
|
907
|
+
with spinner_context(
|
|
908
|
+
ctx,
|
|
909
|
+
"[bold blue]Fetching tools from config…[/bold blue]",
|
|
910
|
+
console_override=console,
|
|
911
|
+
):
|
|
912
|
+
tools = client.mcps.get_mcp_tools_from_config(config_data)
|
|
913
|
+
|
|
914
|
+
title = f"{ICON_TOOL} Tools from config: {Path(config_file).name}"
|
|
915
|
+
return tools, title
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
def _get_tools_from_mcp(ctx: Any, client: Any, mcp_ref: str | None) -> tuple[list[dict[str, Any]], str]:
|
|
919
|
+
"""Get tools from saved MCP.
|
|
920
|
+
|
|
921
|
+
Args:
|
|
922
|
+
ctx: Click context
|
|
923
|
+
client: GlaIP client instance
|
|
924
|
+
mcp_ref: MCP reference (ID or name)
|
|
925
|
+
|
|
926
|
+
Returns:
|
|
927
|
+
Tuple of (tools list, title string)
|
|
928
|
+
"""
|
|
929
|
+
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
930
|
+
|
|
931
|
+
with spinner_context(
|
|
932
|
+
ctx,
|
|
933
|
+
"[bold blue]Fetching MCP tools…[/bold blue]",
|
|
934
|
+
console_override=console,
|
|
935
|
+
):
|
|
936
|
+
tools = client.mcps.get_mcp_tools(mcp.id)
|
|
937
|
+
|
|
938
|
+
title = f"{ICON_TOOL} Tools from MCP: {mcp.name}"
|
|
939
|
+
return tools, title
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
def _output_tool_names(ctx: Any, tools: list[dict[str, Any]]) -> None:
|
|
943
|
+
"""Output only tool names.
|
|
944
|
+
|
|
945
|
+
Args:
|
|
946
|
+
ctx: Click context
|
|
947
|
+
tools: List of tool dictionaries
|
|
948
|
+
"""
|
|
949
|
+
view = get_ctx_value(ctx, "view", "rich")
|
|
950
|
+
tool_names = [tool.get("name", "N/A") for tool in tools]
|
|
951
|
+
|
|
952
|
+
if view == "json":
|
|
953
|
+
handle_json_output(ctx, tool_names)
|
|
954
|
+
elif view == "plain":
|
|
955
|
+
if tool_names:
|
|
956
|
+
for name in tool_names:
|
|
957
|
+
console.print(name, markup=False)
|
|
958
|
+
console.print(f"Total: {len(tool_names)} tools", markup=False)
|
|
959
|
+
else:
|
|
960
|
+
console.print("No tools found", markup=False)
|
|
961
|
+
else:
|
|
962
|
+
if tool_names:
|
|
963
|
+
for name in tool_names:
|
|
964
|
+
console.print(name)
|
|
965
|
+
console.print(f"[dim]Total: {len(tool_names)} tools[/dim]")
|
|
966
|
+
else:
|
|
967
|
+
console.print("[yellow]No tools found[/yellow]")
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
def _transform_tool(tool: dict[str, Any]) -> dict[str, Any]:
|
|
971
|
+
"""Transform a tool dictionary to a display row dictionary.
|
|
972
|
+
|
|
973
|
+
Args:
|
|
974
|
+
tool: Tool dictionary to transform.
|
|
975
|
+
|
|
976
|
+
Returns:
|
|
977
|
+
Dictionary with name and description fields.
|
|
978
|
+
"""
|
|
979
|
+
description = tool.get("description", "N/A")
|
|
980
|
+
if len(description) > MAX_DESCRIPTION_LEN:
|
|
981
|
+
description = description[: MAX_DESCRIPTION_LEN - 3] + "..."
|
|
982
|
+
return {
|
|
983
|
+
"name": tool.get("name", "N/A"),
|
|
984
|
+
"description": description,
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def _output_tools_table(ctx: Any, tools: list[dict[str, Any]], title: str) -> None:
|
|
989
|
+
"""Output tools in table format.
|
|
990
|
+
|
|
991
|
+
Args:
|
|
992
|
+
ctx: Click context
|
|
993
|
+
tools: List of tool dictionaries
|
|
994
|
+
title: Table title
|
|
995
|
+
"""
|
|
996
|
+
columns = [
|
|
997
|
+
("name", "Name", ACCENT_STYLE, None),
|
|
998
|
+
("description", "Description", INFO, 50),
|
|
999
|
+
]
|
|
1000
|
+
|
|
1001
|
+
output_list(
|
|
1002
|
+
ctx,
|
|
1003
|
+
tools,
|
|
1004
|
+
title,
|
|
1005
|
+
columns,
|
|
1006
|
+
_transform_tool,
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
def _validate_tool_command_args(mcp_ref: str | None, config_file: str | None) -> None:
|
|
1011
|
+
"""Validate that exactly one of mcp_ref or config_file is provided.
|
|
1012
|
+
|
|
1013
|
+
Args:
|
|
1014
|
+
mcp_ref: MCP reference (ID or name)
|
|
1015
|
+
config_file: Path to config file
|
|
1016
|
+
|
|
1017
|
+
Raises:
|
|
1018
|
+
ClickException: If validation fails
|
|
1019
|
+
"""
|
|
1020
|
+
if not mcp_ref and not config_file:
|
|
1021
|
+
raise click.ClickException(
|
|
1022
|
+
"Either MCP_REF or --from-config must be provided.\n"
|
|
1023
|
+
"Examples:\n"
|
|
1024
|
+
" aip mcps tools <MCP_ID>\n"
|
|
1025
|
+
" aip mcps tools --from-config mcp-config.json"
|
|
1026
|
+
)
|
|
1027
|
+
if mcp_ref and config_file:
|
|
1028
|
+
raise click.ClickException(
|
|
1029
|
+
"Cannot use both MCP_REF and --from-config at the same time.\n"
|
|
1030
|
+
"Use either:\n"
|
|
1031
|
+
" aip mcps tools <MCP_ID>\n"
|
|
1032
|
+
" aip mcps tools --from-config mcp-config.json"
|
|
1033
|
+
)
|
|
1034
|
+
|
|
1035
|
+
|
|
872
1036
|
@mcps_group.command("tools")
|
|
873
|
-
@click.argument("mcp_ref")
|
|
1037
|
+
@click.argument("mcp_ref", required=False)
|
|
1038
|
+
@click.option(
|
|
1039
|
+
"--from-config",
|
|
1040
|
+
"--config",
|
|
1041
|
+
"config_file",
|
|
1042
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
1043
|
+
help="Get tools from MCP config file without saving to DB (JSON or YAML)",
|
|
1044
|
+
)
|
|
1045
|
+
@click.option(
|
|
1046
|
+
"--names-only",
|
|
1047
|
+
is_flag=True,
|
|
1048
|
+
help="Show only tool names (useful for allowed_tools config)",
|
|
1049
|
+
)
|
|
874
1050
|
@output_flags()
|
|
875
1051
|
@click.pass_context
|
|
876
|
-
def list_tools(ctx: Any, mcp_ref: str) -> None:
|
|
877
|
-
"""List tools available from a specific MCP.
|
|
1052
|
+
def list_tools(ctx: Any, mcp_ref: str | None, config_file: str | None, names_only: bool) -> None:
|
|
1053
|
+
"""List tools available from a specific MCP or config file.
|
|
878
1054
|
|
|
879
1055
|
Args:
|
|
880
1056
|
ctx: Click context containing output format preferences
|
|
881
|
-
mcp_ref: MCP reference (ID or name)
|
|
1057
|
+
mcp_ref: MCP reference (ID or name) - required if --from-config not used
|
|
1058
|
+
config_file: Path to MCP config file - alternative to mcp_ref
|
|
1059
|
+
names_only: Show only tool names instead of full table
|
|
882
1060
|
|
|
883
1061
|
Raises:
|
|
884
1062
|
ClickException: If MCP not found or tools fetch fails
|
|
885
|
-
"""
|
|
886
|
-
try:
|
|
887
|
-
client = get_client(ctx)
|
|
888
|
-
|
|
889
|
-
# Resolve MCP using helper function
|
|
890
|
-
mcp = _resolve_mcp(ctx, client, mcp_ref)
|
|
891
1063
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
"[bold blue]Fetching MCP tools…[/bold blue]",
|
|
896
|
-
console_override=console,
|
|
897
|
-
):
|
|
898
|
-
tools = client.mcps.get_mcp_tools(mcp.id)
|
|
899
|
-
|
|
900
|
-
# Define table columns: (data_key, header, style, width)
|
|
901
|
-
columns = [
|
|
902
|
-
("name", "Name", ACCENT_STYLE, None),
|
|
903
|
-
("description", "Description", INFO, 50),
|
|
904
|
-
]
|
|
1064
|
+
Examples:
|
|
1065
|
+
Get tools from saved MCP:
|
|
1066
|
+
aip mcps tools <MCP_ID>
|
|
905
1067
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
"""Transform a tool dictionary to a display row dictionary.
|
|
1068
|
+
Get tools from config file (without saving to DB):
|
|
1069
|
+
aip mcps tools --from-config mcp-config.json
|
|
909
1070
|
|
|
910
|
-
|
|
911
|
-
|
|
1071
|
+
Get just tool names for allowed_tools config:
|
|
1072
|
+
aip mcps tools <MCP_ID> --names-only
|
|
1073
|
+
"""
|
|
1074
|
+
try:
|
|
1075
|
+
_validate_tool_command_args(mcp_ref, config_file)
|
|
1076
|
+
client = get_client(ctx)
|
|
912
1077
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
"name": tool.get("name", "N/A"),
|
|
918
|
-
"description": tool.get("description", "N/A")[:47] + "..."
|
|
919
|
-
if len(tool.get("description", "")) > 47
|
|
920
|
-
else tool.get("description", "N/A"),
|
|
921
|
-
}
|
|
1078
|
+
if config_file:
|
|
1079
|
+
tools, title = _get_tools_from_config(ctx, client, config_file)
|
|
1080
|
+
else:
|
|
1081
|
+
tools, title = _get_tools_from_mcp(ctx, client, mcp_ref)
|
|
922
1082
|
|
|
923
|
-
|
|
924
|
-
ctx,
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
columns,
|
|
928
|
-
transform_tool,
|
|
929
|
-
)
|
|
1083
|
+
if names_only:
|
|
1084
|
+
_output_tool_names(ctx, tools)
|
|
1085
|
+
else:
|
|
1086
|
+
_output_tools_table(ctx, tools, title)
|
|
930
1087
|
|
|
931
1088
|
except Exception as e:
|
|
932
1089
|
raise click.ClickException(str(e)) from e
|
glaip_sdk/cli/commands/models.py
CHANGED
|
@@ -12,9 +12,8 @@ from rich.console import Console
|
|
|
12
12
|
from glaip_sdk.branding import ACCENT_STYLE, INFO, SUCCESS
|
|
13
13
|
from glaip_sdk.cli.context import output_flags
|
|
14
14
|
from glaip_sdk.cli.utils import (
|
|
15
|
-
get_client,
|
|
16
15
|
output_list,
|
|
17
|
-
|
|
16
|
+
with_client_and_spinner,
|
|
18
17
|
)
|
|
19
18
|
|
|
20
19
|
console = Console()
|
|
@@ -32,12 +31,11 @@ def models_group() -> None:
|
|
|
32
31
|
def list_models(ctx: Any) -> None:
|
|
33
32
|
"""List available language models."""
|
|
34
33
|
try:
|
|
35
|
-
|
|
36
|
-
with spinner_context(
|
|
34
|
+
with with_client_and_spinner(
|
|
37
35
|
ctx,
|
|
38
36
|
"[bold blue]Fetching language models…[/bold blue]",
|
|
39
37
|
console_override=console,
|
|
40
|
-
):
|
|
38
|
+
) as client:
|
|
41
39
|
models = client.list_language_models()
|
|
42
40
|
|
|
43
41
|
# Define table columns: (data_key, header, style, width)
|