glaip-sdk 0.1.3__py3-none-any.whl ā 0.6.19__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 +44 -4
- glaip_sdk/_version.py +9 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1196 -0
- glaip_sdk/branding.py +13 -0
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/auth.py +254 -15
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents.py +213 -73
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +729 -113
- glaip_sdk/cli/commands/mcps.py +241 -72
- glaip_sdk/cli/commands/models.py +11 -5
- glaip_sdk/cli/commands/tools.py +49 -57
- glaip_sdk/cli/commands/transcripts.py +755 -0
- glaip_sdk/cli/config.py +48 -4
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +35 -19
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +241 -121
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/pager.py +9 -10
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +578 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +62 -21
- glaip_sdk/cli/slash/prompt.py +21 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +771 -140
- glaip_sdk/cli/slash/tui/__init__.py +9 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +86 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +876 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +27 -1
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +72 -499
- glaip_sdk/cli/update_notifier.py +14 -5
- glaip_sdk/cli/utils.py +243 -1252
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +2 -1
- glaip_sdk/client/_agent_payloads.py +45 -9
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +291 -35
- glaip_sdk/client/base.py +1 -0
- glaip_sdk/client/main.py +19 -10
- glaip_sdk/client/mcps.py +122 -12
- glaip_sdk/client/run_rendering.py +466 -89
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +155 -10
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/hitl/__init__.py +15 -0
- glaip_sdk/hitl/local.py +151 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +90 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +116 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +232 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +59 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +112 -0
- glaip_sdk/runner/langgraph.py +870 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +95 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +219 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +435 -0
- glaip_sdk/utils/__init__.py +58 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/bundler.py +267 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +39 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +12 -7
- glaip_sdk/utils/import_resolver.py +492 -0
- glaip_sdk/utils/instructions.py +101 -0
- 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 +9 -47
- glaip_sdk/utils/rendering/renderer/base.py +275 -1476
- glaip_sdk/utils/rendering/renderer/debug.py +26 -20
- 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 -440
- 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 +25 -13
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +18 -0
- glaip_sdk/utils/sync.py +142 -0
- glaip_sdk/utils/tool_detection.py +33 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +16 -24
- {glaip_sdk-0.1.3.dist-info ā glaip_sdk-0.6.19.dist-info}/METADATA +56 -21
- glaip_sdk-0.6.19.dist-info/RECORD +163 -0
- {glaip_sdk-0.1.3.dist-info ā glaip_sdk-0.6.19.dist-info}/WHEEL +2 -1
- glaip_sdk-0.6.19.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.6.19.dist-info/top_level.txt +1 -0
- glaip_sdk/models.py +0 -240
- glaip_sdk-0.1.3.dist-info/RECORD +0 -83
- glaip_sdk-0.1.3.dist-info/entry_points.txt +0 -3
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
11
|
from collections.abc import Mapping
|
|
12
|
+
from copy import deepcopy
|
|
12
13
|
from pathlib import Path
|
|
13
14
|
from typing import Any
|
|
14
15
|
|
|
@@ -18,6 +19,7 @@ from rich.console import Console
|
|
|
18
19
|
from glaip_sdk.branding import (
|
|
19
20
|
ACCENT_STYLE,
|
|
20
21
|
ERROR_STYLE,
|
|
22
|
+
HINT_PREFIX_STYLE,
|
|
21
23
|
INFO,
|
|
22
24
|
SUCCESS,
|
|
23
25
|
SUCCESS_STYLE,
|
|
@@ -32,7 +34,8 @@ from glaip_sdk.cli.agent_config import (
|
|
|
32
34
|
from glaip_sdk.cli.agent_config import (
|
|
33
35
|
sanitize_agent_config_for_cli as sanitize_agent_config,
|
|
34
36
|
)
|
|
35
|
-
from glaip_sdk.cli.
|
|
37
|
+
from glaip_sdk.cli.constants import DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
38
|
+
from glaip_sdk.cli.context import get_ctx_value, output_flags
|
|
36
39
|
from glaip_sdk.cli.display import (
|
|
37
40
|
build_resource_result_data,
|
|
38
41
|
display_agent_run_suggestions,
|
|
@@ -44,9 +47,7 @@ from glaip_sdk.cli.display import (
|
|
|
44
47
|
handle_rich_output,
|
|
45
48
|
print_api_error,
|
|
46
49
|
)
|
|
47
|
-
from glaip_sdk.cli.
|
|
48
|
-
export_resource_to_file_with_validation as export_resource_to_file,
|
|
49
|
-
)
|
|
50
|
+
from glaip_sdk.cli.hints import in_slash_mode
|
|
50
51
|
from glaip_sdk.cli.io import (
|
|
51
52
|
fetch_raw_resource_details,
|
|
52
53
|
)
|
|
@@ -64,9 +65,11 @@ from glaip_sdk.cli.utils import (
|
|
|
64
65
|
build_renderer,
|
|
65
66
|
coerce_to_row,
|
|
66
67
|
get_client,
|
|
68
|
+
handle_resource_export,
|
|
67
69
|
output_list,
|
|
68
70
|
output_result,
|
|
69
71
|
spinner_context,
|
|
72
|
+
with_client_and_spinner,
|
|
70
73
|
)
|
|
71
74
|
from glaip_sdk.cli.validators import (
|
|
72
75
|
validate_agent_instruction_cli as validate_agent_instruction,
|
|
@@ -77,7 +80,7 @@ from glaip_sdk.cli.validators import (
|
|
|
77
80
|
from glaip_sdk.cli.validators import (
|
|
78
81
|
validate_timeout_cli as validate_timeout,
|
|
79
82
|
)
|
|
80
|
-
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
|
|
81
84
|
from glaip_sdk.exceptions import AgentTimeoutError
|
|
82
85
|
from glaip_sdk.icons import ICON_AGENT
|
|
83
86
|
from glaip_sdk.utils import format_datetime, is_uuid
|
|
@@ -91,6 +94,8 @@ console = Console()
|
|
|
91
94
|
# Error message constants
|
|
92
95
|
AGENT_NOT_FOUND_ERROR = "Agent not found"
|
|
93
96
|
|
|
97
|
+
# Instruction preview controls
|
|
98
|
+
|
|
94
99
|
|
|
95
100
|
def _safe_agent_attribute(agent: Any, name: str) -> Any:
|
|
96
101
|
"""Return attribute value for ``name`` while filtering Mock sentinels."""
|
|
@@ -143,10 +148,7 @@ def _build_fallback_agent_mapping(agent: Any) -> dict[str, Any]:
|
|
|
143
148
|
"description",
|
|
144
149
|
"model",
|
|
145
150
|
"agent_config",
|
|
146
|
-
"
|
|
147
|
-
"agents",
|
|
148
|
-
"mcps",
|
|
149
|
-
"timeout",
|
|
151
|
+
*[field for field in AGENT_CONFIG_FIELDS if field not in ("name", "instruction", "model")],
|
|
150
152
|
"tool_configs",
|
|
151
153
|
)
|
|
152
154
|
|
|
@@ -310,12 +312,92 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
|
|
|
310
312
|
return result_data
|
|
311
313
|
|
|
312
314
|
|
|
313
|
-
def
|
|
315
|
+
def _clamp_instruction_preview_limit(limit: int | None) -> int:
|
|
316
|
+
"""Normalise preview limit; 0 disables trimming."""
|
|
317
|
+
default = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
|
|
318
|
+
if limit is None: # pragma: no cover
|
|
319
|
+
return default
|
|
320
|
+
try:
|
|
321
|
+
limit_value = int(limit)
|
|
322
|
+
except (TypeError, ValueError): # pragma: no cover - defensive parsing
|
|
323
|
+
return default
|
|
324
|
+
|
|
325
|
+
if limit_value <= 0:
|
|
326
|
+
return 0
|
|
327
|
+
|
|
328
|
+
return limit_value
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _build_instruction_preview(value: Any, limit: int) -> tuple[Any, bool]:
|
|
332
|
+
"""Return a trimmed preview for long instruction strings."""
|
|
333
|
+
if not isinstance(value, str) or limit <= 0: # pragma: no cover
|
|
334
|
+
return value, False
|
|
335
|
+
|
|
336
|
+
if len(value) <= limit:
|
|
337
|
+
return value, False
|
|
338
|
+
|
|
339
|
+
trimmed_value = value[:limit].rstrip()
|
|
340
|
+
preview = f"{trimmed_value}\n\n... (preview trimmed)"
|
|
341
|
+
return preview, True
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _prepare_agent_details_payload(
|
|
345
|
+
data: dict[str, Any],
|
|
346
|
+
*,
|
|
347
|
+
instruction_preview_limit: int,
|
|
348
|
+
) -> tuple[dict[str, Any], bool]:
|
|
349
|
+
"""Return payload ready for rendering plus trim indicator."""
|
|
350
|
+
payload = deepcopy(data)
|
|
351
|
+
trimmed = False
|
|
352
|
+
if instruction_preview_limit > 0:
|
|
353
|
+
preview, trimmed = _build_instruction_preview(payload.get("instruction"), instruction_preview_limit)
|
|
354
|
+
if trimmed:
|
|
355
|
+
payload["instruction"] = preview
|
|
356
|
+
return payload, trimmed
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def _show_instruction_trim_hint(
|
|
360
|
+
ctx: Any,
|
|
361
|
+
*,
|
|
362
|
+
trimmed: bool,
|
|
363
|
+
preview_limit: int,
|
|
364
|
+
) -> None:
|
|
365
|
+
"""Render hint describing how to expand or collapse the instruction preview."""
|
|
366
|
+
if not trimmed or preview_limit <= 0:
|
|
367
|
+
return
|
|
368
|
+
|
|
369
|
+
view = get_ctx_value(ctx, "view", "rich") if ctx is not None else "rich"
|
|
370
|
+
if view != "rich": # pragma: no cover - non-rich view handling
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
suffix = f"[dim](preview: {preview_limit:,} chars)[/]"
|
|
374
|
+
if in_slash_mode(ctx):
|
|
375
|
+
console.print(
|
|
376
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] Use '/details' again to toggle between trimmed and full prompts {suffix}"
|
|
377
|
+
)
|
|
378
|
+
return
|
|
379
|
+
|
|
380
|
+
console.print( # pragma: no cover - fallback hint rendering
|
|
381
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] Run 'aip agents get <agent> --instruction-preview <n>' "
|
|
382
|
+
f"to control prompt preview length {suffix}"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def _display_agent_details(
|
|
387
|
+
ctx: Any,
|
|
388
|
+
client: Any,
|
|
389
|
+
agent: Any,
|
|
390
|
+
*,
|
|
391
|
+
instruction_preview_limit: int | None = None,
|
|
392
|
+
) -> None:
|
|
314
393
|
"""Display full agent details using raw API data to preserve ALL fields."""
|
|
315
394
|
if agent is None:
|
|
316
395
|
handle_rich_output(ctx, markup_text(f"[{ERROR_STYLE}]ā No agent provided[/]"))
|
|
317
396
|
return
|
|
318
397
|
|
|
398
|
+
preview_limit = _clamp_instruction_preview_limit(instruction_preview_limit)
|
|
399
|
+
trimmed_instruction = False
|
|
400
|
+
|
|
319
401
|
# Try to fetch and format raw agent data first
|
|
320
402
|
with spinner_context(
|
|
321
403
|
ctx,
|
|
@@ -327,9 +409,13 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
327
409
|
if formatted_data:
|
|
328
410
|
# Use raw API data - this preserves ALL fields including account_id
|
|
329
411
|
panel_title = f"{ICON_AGENT} {formatted_data.get('name', 'Unknown')}"
|
|
412
|
+
payload, trimmed_instruction = _prepare_agent_details_payload(
|
|
413
|
+
formatted_data,
|
|
414
|
+
instruction_preview_limit=preview_limit,
|
|
415
|
+
)
|
|
330
416
|
output_result(
|
|
331
417
|
ctx,
|
|
332
|
-
|
|
418
|
+
payload,
|
|
333
419
|
title=panel_title,
|
|
334
420
|
)
|
|
335
421
|
else:
|
|
@@ -347,12 +433,22 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
347
433
|
result_data = _format_fallback_agent_data(client, agent)
|
|
348
434
|
|
|
349
435
|
# Display using output_result
|
|
436
|
+
payload, trimmed_instruction = _prepare_agent_details_payload(
|
|
437
|
+
result_data,
|
|
438
|
+
instruction_preview_limit=preview_limit,
|
|
439
|
+
)
|
|
350
440
|
output_result(
|
|
351
441
|
ctx,
|
|
352
|
-
|
|
442
|
+
payload,
|
|
353
443
|
title="Agent Details",
|
|
354
444
|
)
|
|
355
445
|
|
|
446
|
+
_show_instruction_trim_hint(
|
|
447
|
+
ctx,
|
|
448
|
+
trimmed=trimmed_instruction,
|
|
449
|
+
preview_limit=preview_limit,
|
|
450
|
+
)
|
|
451
|
+
|
|
356
452
|
|
|
357
453
|
@click.group(name="agents", no_args_is_help=True)
|
|
358
454
|
def agents_group() -> None:
|
|
@@ -367,26 +463,38 @@ def _resolve_agent(
|
|
|
367
463
|
select: int | None = None,
|
|
368
464
|
interface_preference: str = "fuzzy",
|
|
369
465
|
) -> Any | None:
|
|
370
|
-
"""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.
|
|
371
471
|
|
|
372
472
|
Args:
|
|
373
|
-
ctx: Click context
|
|
374
|
-
client: AIP client instance
|
|
375
|
-
ref: Agent
|
|
376
|
-
select: Pre-selected
|
|
377
|
-
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.
|
|
378
478
|
|
|
379
479
|
Returns:
|
|
380
|
-
|
|
480
|
+
Agent object when found, None when resolution fails.
|
|
381
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
|
|
382
490
|
return resolve_resource_reference(
|
|
383
491
|
ctx,
|
|
384
492
|
client,
|
|
385
493
|
ref,
|
|
386
|
-
"
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"
|
|
494
|
+
resolution_config["resource_type"],
|
|
495
|
+
resolution_config["get_by_id"],
|
|
496
|
+
resolution_config["find_by_name"],
|
|
497
|
+
resolution_config["label"],
|
|
390
498
|
select=select,
|
|
391
499
|
interface_preference=interface_preference,
|
|
392
500
|
)
|
|
@@ -416,19 +524,20 @@ def list_agents(
|
|
|
416
524
|
) -> None:
|
|
417
525
|
"""List agents with optional filtering."""
|
|
418
526
|
try:
|
|
419
|
-
|
|
420
|
-
with spinner_context(
|
|
527
|
+
with with_client_and_spinner(
|
|
421
528
|
ctx,
|
|
422
529
|
"[bold blue]Fetching agentsā¦[/bold blue]",
|
|
423
530
|
console_override=console,
|
|
424
|
-
):
|
|
425
|
-
agents
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
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)
|
|
432
541
|
|
|
433
542
|
# Define table columns: (data_key, header, style, width)
|
|
434
543
|
columns = [
|
|
@@ -441,6 +550,14 @@ def list_agents(
|
|
|
441
550
|
|
|
442
551
|
# Transform function for safe attribute access
|
|
443
552
|
def transform_agent(agent: Any) -> dict[str, Any]:
|
|
553
|
+
"""Transform an agent object to a display row dictionary.
|
|
554
|
+
|
|
555
|
+
Args:
|
|
556
|
+
agent: Agent object to transform.
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
Dictionary with id, name, type, framework, and version fields.
|
|
560
|
+
"""
|
|
444
561
|
row = coerce_to_row(agent, ["id", "name", "type", "framework", "version"])
|
|
445
562
|
# Ensure id is always a string
|
|
446
563
|
row["id"] = str(row["id"])
|
|
@@ -459,7 +576,10 @@ def list_agents(
|
|
|
459
576
|
and len(agents) > 0
|
|
460
577
|
)
|
|
461
578
|
|
|
579
|
+
# Track picker attempt so the fallback table doesn't re-open the palette
|
|
580
|
+
picker_attempted = False
|
|
462
581
|
if interactive_enabled:
|
|
582
|
+
picker_attempted = True
|
|
463
583
|
picked_agent = _fuzzy_pick_for_resources(agents, "agent", "")
|
|
464
584
|
if picked_agent:
|
|
465
585
|
_display_agent_details(ctx, client, picked_agent)
|
|
@@ -474,7 +594,12 @@ def list_agents(
|
|
|
474
594
|
f"{ICON_AGENT} Available Agents",
|
|
475
595
|
columns,
|
|
476
596
|
transform_agent,
|
|
477
|
-
skip_picker=
|
|
597
|
+
skip_picker=(
|
|
598
|
+
not interactive_enabled
|
|
599
|
+
or picker_attempted
|
|
600
|
+
or simple
|
|
601
|
+
or any(param is not None for param in (agent_type, framework, name, version))
|
|
602
|
+
),
|
|
478
603
|
use_pager=False,
|
|
479
604
|
)
|
|
480
605
|
|
|
@@ -490,61 +615,64 @@ def list_agents(
|
|
|
490
615
|
type=click.Path(dir_okay=False, writable=True),
|
|
491
616
|
help="Export complete agent configuration to file (format auto-detected from .json/.yaml extension)",
|
|
492
617
|
)
|
|
618
|
+
@click.option(
|
|
619
|
+
"--instruction-preview",
|
|
620
|
+
type=int,
|
|
621
|
+
default=0,
|
|
622
|
+
show_default=True,
|
|
623
|
+
help="Instruction preview length when printing instructions (0 shows full prompt).",
|
|
624
|
+
)
|
|
493
625
|
@output_flags()
|
|
494
626
|
@click.pass_context
|
|
495
|
-
def get(
|
|
496
|
-
|
|
627
|
+
def get(
|
|
628
|
+
ctx: Any,
|
|
629
|
+
agent_ref: str,
|
|
630
|
+
select: int | None,
|
|
631
|
+
export: str | None,
|
|
632
|
+
instruction_preview: int,
|
|
633
|
+
) -> None:
|
|
634
|
+
r"""Get agent details.
|
|
497
635
|
|
|
636
|
+
\b
|
|
498
637
|
Examples:
|
|
499
638
|
aip agents get my-agent
|
|
500
639
|
aip agents get my-agent --export agent.json # Exports complete configuration as JSON
|
|
501
640
|
aip agents get my-agent --export agent.yaml # Exports complete configuration as YAML
|
|
502
641
|
"""
|
|
503
642
|
try:
|
|
504
|
-
client
|
|
643
|
+
# Initialize API client for agent retrieval
|
|
644
|
+
api_client = get_client(ctx)
|
|
645
|
+
|
|
646
|
+
# Resolve agent reference using questionary interface for better UX
|
|
647
|
+
agent = _resolve_agent(ctx, api_client, agent_ref, select, interface_preference="questionary")
|
|
505
648
|
|
|
506
|
-
|
|
507
|
-
|
|
649
|
+
if not agent:
|
|
650
|
+
raise click.ClickException(f"Agent '{agent_ref}' not found")
|
|
508
651
|
|
|
509
|
-
# Handle export option
|
|
652
|
+
# Handle export option if requested
|
|
510
653
|
if export:
|
|
511
|
-
|
|
512
|
-
# Auto-detect format from file extension
|
|
513
|
-
detected_format = detect_export_format(export_path)
|
|
514
|
-
|
|
515
|
-
# Always export comprehensive data - re-fetch agent with full details
|
|
516
|
-
try:
|
|
517
|
-
with spinner_context(
|
|
518
|
-
ctx,
|
|
519
|
-
"[bold blue]Fetching complete agent dataā¦[/bold blue]",
|
|
520
|
-
console_override=console,
|
|
521
|
-
):
|
|
522
|
-
agent = client.agents.get_agent_by_id(agent.id)
|
|
523
|
-
except Exception as e:
|
|
524
|
-
handle_rich_output(
|
|
525
|
-
ctx,
|
|
526
|
-
markup_text(f"[{WARNING_STYLE}]ā ļø Could not fetch full agent details: {e}[/]"),
|
|
527
|
-
)
|
|
528
|
-
handle_rich_output(
|
|
529
|
-
ctx,
|
|
530
|
-
markup_text(f"[{WARNING_STYLE}]ā ļø Proceeding with available data[/]"),
|
|
531
|
-
)
|
|
532
|
-
|
|
533
|
-
export_resource_to_file(agent, export_path, detected_format)
|
|
534
|
-
handle_rich_output(
|
|
654
|
+
handle_resource_export(
|
|
535
655
|
ctx,
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
656
|
+
agent,
|
|
657
|
+
Path(export),
|
|
658
|
+
resource_type="agent",
|
|
659
|
+
get_by_id_func=api_client.agents.get_agent_by_id,
|
|
660
|
+
console_override=console,
|
|
540
661
|
)
|
|
541
662
|
|
|
542
663
|
# Display full agent details using the standardized helper
|
|
543
|
-
_display_agent_details(
|
|
664
|
+
_display_agent_details(
|
|
665
|
+
ctx,
|
|
666
|
+
api_client,
|
|
667
|
+
agent,
|
|
668
|
+
instruction_preview_limit=instruction_preview,
|
|
669
|
+
)
|
|
544
670
|
|
|
545
671
|
# Show run suggestions via centralized display helper
|
|
546
672
|
handle_rich_output(ctx, display_agent_run_suggestions(agent))
|
|
547
673
|
|
|
674
|
+
except click.ClickException:
|
|
675
|
+
raise
|
|
548
676
|
except Exception as e:
|
|
549
677
|
raise click.ClickException(str(e)) from e
|
|
550
678
|
|
|
@@ -706,10 +834,11 @@ def run(
|
|
|
706
834
|
files: tuple[str, ...] | None,
|
|
707
835
|
verbose: bool,
|
|
708
836
|
) -> None:
|
|
709
|
-
"""Run an agent with input text.
|
|
837
|
+
r"""Run an agent with input text.
|
|
710
838
|
|
|
711
839
|
Usage: aip agents run <agent_ref> <input_text> [OPTIONS]
|
|
712
840
|
|
|
841
|
+
\b
|
|
713
842
|
Examples:
|
|
714
843
|
aip agents run my-agent "Hello world"
|
|
715
844
|
aip agents run agent-123 "Process this data" --timeout 600
|
|
@@ -778,11 +907,13 @@ def run(
|
|
|
778
907
|
|
|
779
908
|
|
|
780
909
|
def _running_in_slash_mode(ctx: Any) -> bool:
|
|
910
|
+
"""Return True if the command is executing inside the slash session."""
|
|
781
911
|
ctx_obj = getattr(ctx, "obj", None)
|
|
782
912
|
return isinstance(ctx_obj, dict) and bool(ctx_obj.get("_slash_session"))
|
|
783
913
|
|
|
784
914
|
|
|
785
915
|
def _emit_verbose_guidance(ctx: Any) -> None:
|
|
916
|
+
"""Explain the modern alternative to the deprecated --verbose flag."""
|
|
786
917
|
if _running_in_slash_mode(ctx):
|
|
787
918
|
message = (
|
|
788
919
|
"[dim]Tip:[/] Verbose streaming has been retired in the command palette. Run the agent normally and open "
|
|
@@ -1037,8 +1168,9 @@ def create(
|
|
|
1037
1168
|
timeout: float | None,
|
|
1038
1169
|
import_file: str | None,
|
|
1039
1170
|
) -> None:
|
|
1040
|
-
"""Create a new agent.
|
|
1171
|
+
r"""Create a new agent.
|
|
1041
1172
|
|
|
1173
|
+
\b
|
|
1042
1174
|
Examples:
|
|
1043
1175
|
aip agents create --name "My Agent" --instruction "You are a helpful assistant"
|
|
1044
1176
|
aip agents create --import agent.json
|
|
@@ -1232,8 +1364,9 @@ def update(
|
|
|
1232
1364
|
timeout: float | None,
|
|
1233
1365
|
import_file: str | None,
|
|
1234
1366
|
) -> None:
|
|
1235
|
-
"""Update an existing agent.
|
|
1367
|
+
r"""Update an existing agent.
|
|
1236
1368
|
|
|
1369
|
+
\b
|
|
1237
1370
|
Examples:
|
|
1238
1371
|
aip agents update my-agent --instruction "New instruction"
|
|
1239
1372
|
aip agents update my-agent --import agent.json
|
|
@@ -1257,6 +1390,12 @@ def update(
|
|
|
1257
1390
|
|
|
1258
1391
|
if merged_data:
|
|
1259
1392
|
_handle_update_import_config(import_file, merged_data, update_data)
|
|
1393
|
+
# Ensure instruction from import file is included if not already set via CLI
|
|
1394
|
+
# This handles the case where instruction is None in CLI args but exists in import file
|
|
1395
|
+
if import_file and (instruction is None or "instruction" not in update_data):
|
|
1396
|
+
import_instruction = merged_data.get("instruction")
|
|
1397
|
+
if import_instruction is not None:
|
|
1398
|
+
update_data["instruction"] = import_instruction
|
|
1260
1399
|
|
|
1261
1400
|
if not update_data:
|
|
1262
1401
|
raise click.ClickException("No update fields specified")
|
|
@@ -1327,7 +1466,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1327
1466
|
@output_flags()
|
|
1328
1467
|
@click.pass_context
|
|
1329
1468
|
def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
1330
|
-
"""Sync agents with LangFlow server flows.
|
|
1469
|
+
r"""Sync agents with LangFlow server flows.
|
|
1331
1470
|
|
|
1332
1471
|
This command fetches all flows from the configured LangFlow server and
|
|
1333
1472
|
creates/updates corresponding agents in the platform.
|
|
@@ -1336,6 +1475,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1336
1475
|
- Command options (--base-url, --api-key)
|
|
1337
1476
|
- Environment variables (LANGFLOW_BASE_URL, LANGFLOW_API_KEY)
|
|
1338
1477
|
|
|
1478
|
+
\b
|
|
1339
1479
|
Examples:
|
|
1340
1480
|
aip agents sync-langflow
|
|
1341
1481
|
aip agents sync-langflow --base-url https://my-langflow.com --api-key my-key
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Shared helpers for configuration/account flows."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.text import Text
|
|
11
|
+
from glaip_sdk.branding import PRIMARY, SUCCESS_STYLE, WARNING_STYLE, AIPBranding
|
|
12
|
+
from glaip_sdk.cli.utils import sdk_version
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
15
|
+
from glaip_sdk import Client
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def render_branding_header(console: Console, rule_text: str) -> None:
|
|
19
|
+
"""Render the standard CLI branding header with a custom rule text."""
|
|
20
|
+
branding = AIPBranding.create_from_sdk(sdk_version=sdk_version(), package_name="glaip-sdk")
|
|
21
|
+
heading = "[bold]>_ GDP Labs AI Agents Package (AIP CLI)[/bold]"
|
|
22
|
+
console.print(heading)
|
|
23
|
+
console.print()
|
|
24
|
+
console.print(branding.get_welcome_banner())
|
|
25
|
+
console.rule(rule_text, style=PRIMARY)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def check_connection(
|
|
29
|
+
api_url: str,
|
|
30
|
+
api_key: str,
|
|
31
|
+
console: Console,
|
|
32
|
+
*,
|
|
33
|
+
abort_on_error: bool = False,
|
|
34
|
+
extra_hint: str | None = None,
|
|
35
|
+
) -> bool:
|
|
36
|
+
"""Test connectivity and report results.
|
|
37
|
+
|
|
38
|
+
Returns True on success, False on handled failures. Raises click.Abort when
|
|
39
|
+
abort_on_error is True and a fatal error occurs.
|
|
40
|
+
"""
|
|
41
|
+
console.print("\nš Testing connection...")
|
|
42
|
+
client: Client | None = None
|
|
43
|
+
try:
|
|
44
|
+
# Import lazily to avoid pulling in SDK dependencies during CLI startup.
|
|
45
|
+
from glaip_sdk import Client # noqa: PLC0415
|
|
46
|
+
|
|
47
|
+
client = Client(api_url=api_url, api_key=api_key)
|
|
48
|
+
try:
|
|
49
|
+
agents = client.list_agents()
|
|
50
|
+
console.print(Text(f"ā
Connection successful! Found {len(agents)} agents", style=SUCCESS_STYLE))
|
|
51
|
+
return True
|
|
52
|
+
except Exception as exc: # pragma: no cover - API failures depend on network
|
|
53
|
+
console.print(Text(f"ā ļø Connection established but API call failed: {exc}", style=WARNING_STYLE))
|
|
54
|
+
console.print(" You may need to check your API permissions or network access")
|
|
55
|
+
if extra_hint:
|
|
56
|
+
console.print(extra_hint)
|
|
57
|
+
if abort_on_error:
|
|
58
|
+
raise click.Abort() from exc
|
|
59
|
+
return False
|
|
60
|
+
except Exception as exc:
|
|
61
|
+
console.print(Text(f"ā Connection failed: {exc}"))
|
|
62
|
+
console.print(" Please check your API URL and key")
|
|
63
|
+
if extra_hint:
|
|
64
|
+
console.print(extra_hint)
|
|
65
|
+
if abort_on_error:
|
|
66
|
+
raise click.Abort() from exc
|
|
67
|
+
return False
|
|
68
|
+
finally:
|
|
69
|
+
if client is not None:
|
|
70
|
+
client.close()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def check_connection_with_reason(
|
|
74
|
+
api_url: str,
|
|
75
|
+
api_key: str,
|
|
76
|
+
*,
|
|
77
|
+
abort_on_error: bool = False,
|
|
78
|
+
) -> tuple[bool, str]:
|
|
79
|
+
"""Test connectivity and return structured reason."""
|
|
80
|
+
client: Client | None = None
|
|
81
|
+
try:
|
|
82
|
+
# Import lazily to avoid pulling in SDK dependencies during CLI startup.
|
|
83
|
+
from glaip_sdk import Client # noqa: PLC0415
|
|
84
|
+
|
|
85
|
+
client = Client(api_url=api_url, api_key=api_key)
|
|
86
|
+
try:
|
|
87
|
+
client.list_agents()
|
|
88
|
+
return True, ""
|
|
89
|
+
except Exception as exc: # pragma: no cover - API failures depend on network
|
|
90
|
+
if abort_on_error:
|
|
91
|
+
raise click.Abort() from exc
|
|
92
|
+
return False, f"api_failed: {exc}"
|
|
93
|
+
except Exception as exc:
|
|
94
|
+
# Log unexpected exceptions in debug while keeping CLI-friendly messaging
|
|
95
|
+
logging.getLogger(__name__).debug("Unexpected connection error", exc_info=exc)
|
|
96
|
+
if abort_on_error:
|
|
97
|
+
raise click.Abort() from exc
|
|
98
|
+
return False, f"connection_failed: {exc}"
|
|
99
|
+
finally:
|
|
100
|
+
if client is not None:
|
|
101
|
+
try:
|
|
102
|
+
client.close()
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|