glaip-sdk 0.0.19__py3-none-any.whl → 0.1.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/_version.py +2 -2
- glaip_sdk/branding.py +27 -2
- glaip_sdk/cli/auth.py +93 -28
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/agents.py +127 -21
- glaip_sdk/cli/commands/configure.py +141 -90
- glaip_sdk/cli/commands/mcps.py +82 -31
- glaip_sdk/cli/commands/models.py +4 -3
- glaip_sdk/cli/commands/tools.py +27 -14
- glaip_sdk/cli/commands/update.py +66 -0
- glaip_sdk/cli/config.py +13 -2
- glaip_sdk/cli/display.py +35 -26
- glaip_sdk/cli/io.py +14 -5
- glaip_sdk/cli/main.py +185 -73
- glaip_sdk/cli/pager.py +2 -1
- glaip_sdk/cli/resolution.py +4 -1
- glaip_sdk/cli/slash/__init__.py +3 -4
- glaip_sdk/cli/slash/agent_session.py +88 -36
- glaip_sdk/cli/slash/prompt.py +20 -48
- glaip_sdk/cli/slash/session.py +437 -189
- glaip_sdk/cli/transcript/__init__.py +71 -0
- glaip_sdk/cli/transcript/cache.py +338 -0
- glaip_sdk/cli/transcript/capture.py +278 -0
- glaip_sdk/cli/transcript/export.py +38 -0
- glaip_sdk/cli/transcript/launcher.py +79 -0
- glaip_sdk/cli/transcript/viewer.py +794 -0
- glaip_sdk/cli/update_notifier.py +29 -5
- glaip_sdk/cli/utils.py +255 -74
- glaip_sdk/client/agents.py +3 -1
- glaip_sdk/client/run_rendering.py +126 -21
- glaip_sdk/icons.py +25 -0
- glaip_sdk/models.py +6 -0
- glaip_sdk/rich_components.py +29 -1
- glaip_sdk/utils/__init__.py +1 -1
- glaip_sdk/utils/client_utils.py +6 -4
- glaip_sdk/utils/display.py +61 -32
- glaip_sdk/utils/rendering/formatting.py +55 -11
- glaip_sdk/utils/rendering/models.py +15 -2
- glaip_sdk/utils/rendering/renderer/__init__.py +0 -2
- glaip_sdk/utils/rendering/renderer/base.py +1287 -227
- glaip_sdk/utils/rendering/renderer/config.py +3 -5
- glaip_sdk/utils/rendering/renderer/debug.py +73 -16
- glaip_sdk/utils/rendering/renderer/panels.py +27 -15
- glaip_sdk/utils/rendering/renderer/progress.py +61 -38
- glaip_sdk/utils/rendering/renderer/stream.py +3 -3
- glaip_sdk/utils/rendering/renderer/toggle.py +184 -0
- glaip_sdk/utils/rendering/step_tree_state.py +102 -0
- glaip_sdk/utils/rendering/steps.py +944 -16
- glaip_sdk/utils/serialization.py +5 -2
- glaip_sdk/utils/validation.py +1 -2
- {glaip_sdk-0.0.19.dist-info → glaip_sdk-0.1.0.dist-info}/METADATA +12 -1
- glaip_sdk-0.1.0.dist-info/RECORD +82 -0
- glaip_sdk/utils/rich_utils.py +0 -29
- glaip_sdk-0.0.19.dist-info/RECORD +0 -73
- {glaip_sdk-0.0.19.dist-info → glaip_sdk-0.1.0.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.0.19.dist-info → glaip_sdk-0.1.0.dist-info}/entry_points.txt +0 -0
glaip_sdk/_version.py
CHANGED
|
@@ -6,6 +6,8 @@ Falls back to a dev marker when running from source without installation.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
9
11
|
try:
|
|
10
12
|
from importlib.metadata import PackageNotFoundError, version # Python 3.8+
|
|
11
13
|
except Exception: # pragma: no cover - extremely unlikely
|
|
@@ -38,8 +40,6 @@ def _try_get_dev_version() -> str | None:
|
|
|
38
40
|
return None
|
|
39
41
|
|
|
40
42
|
try:
|
|
41
|
-
from pathlib import Path
|
|
42
|
-
|
|
43
43
|
here = Path(__file__).resolve()
|
|
44
44
|
root = here.parent.parent # project root (contains pyproject.toml)
|
|
45
45
|
pyproject = root / "pyproject.toml"
|
glaip_sdk/branding.py
CHANGED
|
@@ -36,9 +36,27 @@ SECONDARY_DARK = "#003A5C" # Darkest variant for emphasis
|
|
|
36
36
|
SECONDARY_MEDIUM = "#005CB8" # Medium variant for UI elements
|
|
37
37
|
SECONDARY_LIGHT = "#40B4E5" # Light variant for highlights
|
|
38
38
|
|
|
39
|
+
# Neutral companion palette (optimized for dark terminals)
|
|
40
|
+
SUCCESS = "#7FA089" # Muted teal-green for success messaging
|
|
41
|
+
WARNING = "#C3A46F" # Soft amber for warnings
|
|
42
|
+
ERROR = "#C97B6C" # Tempered coral-red for errors
|
|
43
|
+
INFO = "#9CA3AF" # Cool grey for informational accents
|
|
44
|
+
NEUTRAL = "#D1D5DB" # Light grey for muted text and dividers
|
|
45
|
+
|
|
39
46
|
BORDER = PRIMARY # Keep borders aligned with primary brand tone
|
|
40
47
|
TITLE_STYLE = f"bold {PRIMARY}"
|
|
41
48
|
LABEL = "bold"
|
|
49
|
+
SUCCESS_STYLE = f"bold {SUCCESS}"
|
|
50
|
+
WARNING_STYLE = f"bold {WARNING}"
|
|
51
|
+
ERROR_STYLE = f"bold {ERROR}"
|
|
52
|
+
INFO_STYLE = f"bold {INFO}"
|
|
53
|
+
ACCENT_STYLE = INFO # For subdued inline highlights
|
|
54
|
+
|
|
55
|
+
# Hint styling (slash command helpers, tips, quick actions)
|
|
56
|
+
HINT_TITLE_STYLE = f"bold {SECONDARY_LIGHT}"
|
|
57
|
+
HINT_COMMAND_STYLE = f"bold {SECONDARY_LIGHT}"
|
|
58
|
+
HINT_DESCRIPTION_COLOR = NEUTRAL
|
|
59
|
+
HINT_PREFIX_STYLE = INFO_STYLE
|
|
42
60
|
|
|
43
61
|
|
|
44
62
|
class AIPBranding:
|
|
@@ -118,11 +136,17 @@ GDP Labs AI Agents Package
|
|
|
118
136
|
"architecture": platform.architecture()[0],
|
|
119
137
|
}
|
|
120
138
|
|
|
121
|
-
def display_welcome_panel(
|
|
139
|
+
def display_welcome_panel(
|
|
140
|
+
self,
|
|
141
|
+
title: str = "Welcome to AIP",
|
|
142
|
+
*,
|
|
143
|
+
console: Console | None = None,
|
|
144
|
+
) -> None:
|
|
122
145
|
"""Display a welcome panel with branding.
|
|
123
146
|
|
|
124
147
|
Args:
|
|
125
148
|
title: Custom title for the welcome panel
|
|
149
|
+
console: Optional console instance to print to. If None, uses self.console
|
|
126
150
|
"""
|
|
127
151
|
banner = self.get_welcome_banner()
|
|
128
152
|
panel = AIPPanel(
|
|
@@ -131,7 +155,8 @@ GDP Labs AI Agents Package
|
|
|
131
155
|
border_style=BORDER,
|
|
132
156
|
padding=(1, 2),
|
|
133
157
|
)
|
|
134
|
-
self.console
|
|
158
|
+
target_console = console or self.console
|
|
159
|
+
target_console.print(panel)
|
|
135
160
|
|
|
136
161
|
def display_version_panel(self) -> None:
|
|
137
162
|
"""Display a panel with comprehensive version information."""
|
glaip_sdk/cli/auth.py
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
This module provides utilities for preparing authentication data for export,
|
|
4
4
|
including interactive secret capture and placeholder generation.
|
|
5
5
|
|
|
6
|
+
These helpers are distinct from the AIP CLI's own authentication, which always
|
|
7
|
+
relies on the API URL and API key managed via ``aip configure`` / `AIP_API_*`
|
|
8
|
+
environment variables.
|
|
9
|
+
|
|
6
10
|
Authors:
|
|
7
11
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
8
12
|
"""
|
|
@@ -13,6 +17,9 @@ from typing import Any
|
|
|
13
17
|
import click
|
|
14
18
|
from rich.console import Console
|
|
15
19
|
|
|
20
|
+
from glaip_sdk.branding import HINT_PREFIX_STYLE, WARNING_STYLE
|
|
21
|
+
from glaip_sdk.cli.utils import command_hint, format_command_hint
|
|
22
|
+
|
|
16
23
|
|
|
17
24
|
def prepare_authentication_export(
|
|
18
25
|
auth: dict[str, Any] | None,
|
|
@@ -92,21 +99,19 @@ def _get_token_value(
|
|
|
92
99
|
The token string, either provided by the user or the placeholder.
|
|
93
100
|
"""
|
|
94
101
|
if prompt_for_secrets:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"Please provide the token.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
show_default=False,
|
|
102
|
+
return _prompt_secret_with_placeholder(
|
|
103
|
+
console,
|
|
104
|
+
warning_message="Bearer token is missing or redacted. Please provide the token.",
|
|
105
|
+
prompt_message="Bearer token (leave blank for placeholder)",
|
|
106
|
+
placeholder=placeholder,
|
|
107
|
+
tip_cli_command="configure",
|
|
108
|
+
tip_slash_command="configure",
|
|
103
109
|
)
|
|
104
|
-
return token_value.strip() or placeholder
|
|
105
110
|
|
|
106
111
|
if not click.get_text_stream("stdin").isatty():
|
|
107
112
|
console.print(
|
|
108
|
-
"[
|
|
109
|
-
"using placeholder for bearer token[/
|
|
113
|
+
f"[{WARNING_STYLE}]⚠️ Non-interactive mode: "
|
|
114
|
+
"using placeholder for bearer token[/]"
|
|
110
115
|
)
|
|
111
116
|
return placeholder
|
|
112
117
|
|
|
@@ -205,20 +210,19 @@ def _get_api_key_value(
|
|
|
205
210
|
The API key value, either provided by the user or the placeholder.
|
|
206
211
|
"""
|
|
207
212
|
if prompt_for_secrets:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
213
|
+
return _prompt_secret_with_placeholder(
|
|
214
|
+
console,
|
|
215
|
+
warning_message=f"API key value for '{key_name}' is missing or redacted.",
|
|
216
|
+
prompt_message=f"API key value for '{key_name}' (leave blank for placeholder)",
|
|
217
|
+
placeholder=placeholder,
|
|
218
|
+
tip_cli_command="configure api-key",
|
|
219
|
+
tip_slash_command="configure",
|
|
215
220
|
)
|
|
216
|
-
return key_value.strip() or placeholder
|
|
217
221
|
|
|
218
222
|
if not click.get_text_stream("stdin").isatty():
|
|
219
223
|
console.print(
|
|
220
|
-
f"[
|
|
221
|
-
f"using placeholder for API key '{key_name}'[/
|
|
224
|
+
f"[{WARNING_STYLE}]⚠️ Non-interactive mode: "
|
|
225
|
+
f"using placeholder for API key '{key_name}'[/]"
|
|
222
226
|
)
|
|
223
227
|
return placeholder
|
|
224
228
|
|
|
@@ -362,17 +366,18 @@ def _prompt_or_placeholder(
|
|
|
362
366
|
The provided value or the placeholder.
|
|
363
367
|
"""
|
|
364
368
|
if prompt_for_secrets:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
f"
|
|
368
|
-
|
|
369
|
-
|
|
369
|
+
return _prompt_secret_with_placeholder(
|
|
370
|
+
console,
|
|
371
|
+
warning_message=f"Header '{name}' is missing or redacted.",
|
|
372
|
+
prompt_message=f"Value for header '{name}' (leave blank for placeholder)",
|
|
373
|
+
placeholder=placeholder,
|
|
374
|
+
tip_cli_command="configure",
|
|
375
|
+
tip_slash_command="configure",
|
|
370
376
|
)
|
|
371
|
-
return value.strip() or placeholder
|
|
372
377
|
|
|
373
378
|
if not click.get_text_stream("stdin").isatty():
|
|
374
379
|
console.print(
|
|
375
|
-
f"[
|
|
380
|
+
f"[{WARNING_STYLE}]⚠️ Non-interactive mode: using placeholder for header '{name}'[/]"
|
|
376
381
|
)
|
|
377
382
|
return placeholder
|
|
378
383
|
|
|
@@ -412,3 +417,63 @@ def _build_custom_headers(
|
|
|
412
417
|
)
|
|
413
418
|
|
|
414
419
|
return headers
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def _prompt_secret_with_placeholder(
|
|
423
|
+
console: Console,
|
|
424
|
+
*,
|
|
425
|
+
warning_message: str,
|
|
426
|
+
prompt_message: str,
|
|
427
|
+
placeholder: str,
|
|
428
|
+
tip_cli_command: str | None = "configure",
|
|
429
|
+
tip_slash_command: str | None = "configure",
|
|
430
|
+
mask_input: bool = True,
|
|
431
|
+
retry_limit: int = 1,
|
|
432
|
+
) -> str:
|
|
433
|
+
"""Prompt for a secret value with masking, retries, and placeholder fallback.
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
console: Rich console used to render messaging.
|
|
437
|
+
warning_message: Message shown before prompting (rendered with warning style).
|
|
438
|
+
prompt_message: The message passed to :func:`click.prompt`.
|
|
439
|
+
placeholder: Placeholder value inserted when the user skips input.
|
|
440
|
+
tip_cli_command: CLI command (without ``aip`` prefix) used to build hints.
|
|
441
|
+
tip_slash_command: Slash command counterpart used in hints.
|
|
442
|
+
mask_input: Whether to hide user input while typing.
|
|
443
|
+
retry_limit: Number of additional attempts when the user submits empty input.
|
|
444
|
+
|
|
445
|
+
Returns:
|
|
446
|
+
The value entered by the user or the provided placeholder.
|
|
447
|
+
"""
|
|
448
|
+
console.print(f"[{WARNING_STYLE}]{warning_message}[/]")
|
|
449
|
+
|
|
450
|
+
tip = command_hint(tip_cli_command, tip_slash_command)
|
|
451
|
+
if tip:
|
|
452
|
+
console.print(
|
|
453
|
+
f"[{HINT_PREFIX_STYLE}]Tip:[/] use {format_command_hint(tip) or tip} later if you want to update these credentials."
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
attempts = 0
|
|
457
|
+
while attempts <= retry_limit:
|
|
458
|
+
response = click.prompt(
|
|
459
|
+
prompt_message,
|
|
460
|
+
default="",
|
|
461
|
+
show_default=False,
|
|
462
|
+
hide_input=mask_input,
|
|
463
|
+
)
|
|
464
|
+
value = response.strip()
|
|
465
|
+
if value:
|
|
466
|
+
return value
|
|
467
|
+
|
|
468
|
+
if attempts < retry_limit:
|
|
469
|
+
console.print(
|
|
470
|
+
f"[{WARNING_STYLE}]No value entered. Enter a value or press Enter again to use the placeholder.[/]"
|
|
471
|
+
)
|
|
472
|
+
attempts += 1
|
|
473
|
+
continue
|
|
474
|
+
|
|
475
|
+
console.print("[dim]Using placeholder value.[/dim]")
|
|
476
|
+
return placeholder
|
|
477
|
+
|
|
478
|
+
# This line is unreachable as the loop always returns
|
|
479
|
+
# return placeholder
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""CLI commands package exports."""
|
|
2
2
|
|
|
3
|
-
from glaip_sdk.cli.commands import agents, configure, mcps, models, tools
|
|
3
|
+
from glaip_sdk.cli.commands import agents, configure, mcps, models, tools, update
|
|
4
4
|
|
|
5
|
-
__all__ = ["agents", "configure", "mcps", "models", "tools"]
|
|
5
|
+
__all__ = ["agents", "configure", "mcps", "models", "tools", "update"]
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -4,6 +4,8 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
7
9
|
import json
|
|
8
10
|
import os
|
|
9
11
|
from collections.abc import Mapping
|
|
@@ -13,6 +15,14 @@ from typing import Any
|
|
|
13
15
|
import click
|
|
14
16
|
from rich.console import Console
|
|
15
17
|
|
|
18
|
+
from glaip_sdk.branding import (
|
|
19
|
+
ACCENT_STYLE,
|
|
20
|
+
ERROR_STYLE,
|
|
21
|
+
INFO,
|
|
22
|
+
SUCCESS,
|
|
23
|
+
SUCCESS_STYLE,
|
|
24
|
+
WARNING_STYLE,
|
|
25
|
+
)
|
|
16
26
|
from glaip_sdk.cli.agent_config import (
|
|
17
27
|
merge_agent_config_with_cli_args as merge_import_with_cli_args,
|
|
18
28
|
)
|
|
@@ -45,6 +55,10 @@ from glaip_sdk.cli.io import (
|
|
|
45
55
|
)
|
|
46
56
|
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
47
57
|
from glaip_sdk.cli.rich_helpers import markup_text, print_markup
|
|
58
|
+
from glaip_sdk.cli.transcript import (
|
|
59
|
+
maybe_launch_post_run_viewer,
|
|
60
|
+
store_transcript_for_session,
|
|
61
|
+
)
|
|
48
62
|
from glaip_sdk.cli.utils import (
|
|
49
63
|
_fuzzy_pick_for_resources,
|
|
50
64
|
build_renderer,
|
|
@@ -65,9 +79,11 @@ from glaip_sdk.cli.validators import (
|
|
|
65
79
|
)
|
|
66
80
|
from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT, DEFAULT_MODEL
|
|
67
81
|
from glaip_sdk.exceptions import AgentTimeoutError
|
|
82
|
+
from glaip_sdk.icons import ICON_AGENT
|
|
68
83
|
from glaip_sdk.utils import format_datetime, is_uuid
|
|
69
84
|
from glaip_sdk.utils.agent_config import normalize_agent_config_for_import
|
|
70
85
|
from glaip_sdk.utils.import_export import convert_export_to_import_format
|
|
86
|
+
from glaip_sdk.utils.rendering.renderer.toggle import TranscriptToggleController
|
|
71
87
|
from glaip_sdk.utils.validation import coerce_timeout
|
|
72
88
|
|
|
73
89
|
console = Console()
|
|
@@ -168,17 +184,41 @@ def _fetch_full_agent_details(client: Any, agent: Any) -> Any | None:
|
|
|
168
184
|
return agent
|
|
169
185
|
|
|
170
186
|
|
|
187
|
+
def _normalise_model_name(value: Any) -> str | None:
|
|
188
|
+
"""Return a cleaned model name or None when not usable."""
|
|
189
|
+
if value is None:
|
|
190
|
+
return None
|
|
191
|
+
if isinstance(value, str):
|
|
192
|
+
cleaned = value.strip()
|
|
193
|
+
return cleaned or None
|
|
194
|
+
if isinstance(value, bool):
|
|
195
|
+
return None
|
|
196
|
+
return str(value)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _model_from_config(agent: Any) -> str | None:
|
|
200
|
+
"""Extract a usable model name from an agent's configuration mapping."""
|
|
201
|
+
config = getattr(agent, "agent_config", None)
|
|
202
|
+
if not config or not isinstance(config, dict):
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
for key in ("lm_name", "model"):
|
|
206
|
+
normalised = _normalise_model_name(config.get(key))
|
|
207
|
+
if normalised:
|
|
208
|
+
return normalised
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
|
|
171
212
|
def _get_agent_model_name(agent: Any) -> str | None:
|
|
172
213
|
"""Extract model name from agent configuration."""
|
|
173
|
-
|
|
174
|
-
if
|
|
175
|
-
|
|
176
|
-
return agent.agent_config.get("lm_name") or agent.agent_config.get("model")
|
|
214
|
+
config_model = _model_from_config(agent)
|
|
215
|
+
if config_model:
|
|
216
|
+
return config_model
|
|
177
217
|
|
|
178
|
-
|
|
179
|
-
|
|
218
|
+
normalised_attr = _normalise_model_name(getattr(agent, "model", None))
|
|
219
|
+
if normalised_attr:
|
|
220
|
+
return normalised_attr
|
|
180
221
|
|
|
181
|
-
# Default fallback
|
|
182
222
|
return DEFAULT_MODEL
|
|
183
223
|
|
|
184
224
|
|
|
@@ -198,7 +238,7 @@ def _resolve_resources_by_name(
|
|
|
198
238
|
List of resolved resource IDs
|
|
199
239
|
"""
|
|
200
240
|
out = []
|
|
201
|
-
for ref in
|
|
241
|
+
for ref in items or ():
|
|
202
242
|
if is_uuid(ref):
|
|
203
243
|
out.append(ref)
|
|
204
244
|
continue
|
|
@@ -275,7 +315,7 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
|
|
|
275
315
|
def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
276
316
|
"""Display full agent details using raw API data to preserve ALL fields."""
|
|
277
317
|
if agent is None:
|
|
278
|
-
handle_rich_output(ctx, markup_text("[
|
|
318
|
+
handle_rich_output(ctx, markup_text(f"[{ERROR_STYLE}]❌ No agent provided[/]"))
|
|
279
319
|
return
|
|
280
320
|
|
|
281
321
|
# Try to fetch and format raw agent data first
|
|
@@ -288,7 +328,7 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
288
328
|
|
|
289
329
|
if formatted_data:
|
|
290
330
|
# Use raw API data - this preserves ALL fields including account_id
|
|
291
|
-
panel_title = f"
|
|
331
|
+
panel_title = f"{ICON_AGENT} {formatted_data.get('name', 'Unknown')}"
|
|
292
332
|
output_result(
|
|
293
333
|
ctx,
|
|
294
334
|
formatted_data,
|
|
@@ -298,7 +338,7 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
|
|
|
298
338
|
# Fall back to Pydantic model data if raw fetch fails
|
|
299
339
|
handle_rich_output(
|
|
300
340
|
ctx,
|
|
301
|
-
markup_text("[
|
|
341
|
+
markup_text(f"[{WARNING_STYLE}]Falling back to Pydantic model data[/]"),
|
|
302
342
|
)
|
|
303
343
|
|
|
304
344
|
with spinner_context(
|
|
@@ -401,10 +441,10 @@ def list_agents(
|
|
|
401
441
|
# Define table columns: (data_key, header, style, width)
|
|
402
442
|
columns = [
|
|
403
443
|
("id", "ID", "dim", 36),
|
|
404
|
-
("name", "Name",
|
|
405
|
-
("type", "Type",
|
|
406
|
-
("framework", "Framework",
|
|
407
|
-
("version", "Version",
|
|
444
|
+
("name", "Name", ACCENT_STYLE, None),
|
|
445
|
+
("type", "Type", WARNING_STYLE, None),
|
|
446
|
+
("framework", "Framework", INFO, None),
|
|
447
|
+
("version", "Version", SUCCESS, None),
|
|
408
448
|
]
|
|
409
449
|
|
|
410
450
|
# Transform function for safe attribute access
|
|
@@ -439,7 +479,7 @@ def list_agents(
|
|
|
439
479
|
output_list(
|
|
440
480
|
ctx,
|
|
441
481
|
agents,
|
|
442
|
-
"
|
|
482
|
+
f"{ICON_AGENT} Available Agents",
|
|
443
483
|
columns,
|
|
444
484
|
transform_agent,
|
|
445
485
|
skip_picker=simple
|
|
@@ -497,19 +537,21 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
|
|
|
497
537
|
handle_rich_output(
|
|
498
538
|
ctx,
|
|
499
539
|
markup_text(
|
|
500
|
-
f"[
|
|
540
|
+
f"[{WARNING_STYLE}]⚠️ Could not fetch full agent details: {e}[/]"
|
|
501
541
|
),
|
|
502
542
|
)
|
|
503
543
|
handle_rich_output(
|
|
504
544
|
ctx,
|
|
505
|
-
markup_text(
|
|
545
|
+
markup_text(
|
|
546
|
+
f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]"
|
|
547
|
+
),
|
|
506
548
|
)
|
|
507
549
|
|
|
508
550
|
export_resource_to_file(agent, export_path, detected_format)
|
|
509
551
|
handle_rich_output(
|
|
510
552
|
ctx,
|
|
511
553
|
markup_text(
|
|
512
|
-
f"[
|
|
554
|
+
f"[{SUCCESS_STYLE}]✅ Complete agent configuration exported to: {export_path} (format: {detected_format})[/]"
|
|
513
555
|
),
|
|
514
556
|
)
|
|
515
557
|
|
|
@@ -557,6 +599,23 @@ def _setup_run_renderer(ctx: Any, save: str | None, verbose: bool) -> Any:
|
|
|
557
599
|
)
|
|
558
600
|
|
|
559
601
|
|
|
602
|
+
def _maybe_attach_transcript_toggle(ctx: Any, renderer: Any) -> None:
|
|
603
|
+
"""Attach transcript toggle controller when interactive TTY is available."""
|
|
604
|
+
if renderer is None:
|
|
605
|
+
return
|
|
606
|
+
|
|
607
|
+
console_obj = getattr(renderer, "console", None)
|
|
608
|
+
if console_obj is None or not getattr(console_obj, "is_terminal", False):
|
|
609
|
+
return
|
|
610
|
+
|
|
611
|
+
tty_enabled = bool(get_ctx_value(ctx, "tty", True))
|
|
612
|
+
if not tty_enabled:
|
|
613
|
+
return
|
|
614
|
+
|
|
615
|
+
controller = TranscriptToggleController(enabled=True)
|
|
616
|
+
renderer.transcript_controller = controller
|
|
617
|
+
|
|
618
|
+
|
|
560
619
|
def _prepare_run_kwargs(
|
|
561
620
|
agent: Any,
|
|
562
621
|
final_input_text: str,
|
|
@@ -621,7 +680,9 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
|
|
|
621
680
|
|
|
622
681
|
with open(save, "w", encoding="utf-8") as f:
|
|
623
682
|
f.write(content)
|
|
624
|
-
print_markup(
|
|
683
|
+
print_markup(
|
|
684
|
+
f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console
|
|
685
|
+
)
|
|
625
686
|
|
|
626
687
|
|
|
627
688
|
@agents_group.command()
|
|
@@ -678,6 +739,10 @@ def run(
|
|
|
678
739
|
"""
|
|
679
740
|
final_input_text = _validate_run_input(input_option, input_text)
|
|
680
741
|
|
|
742
|
+
if verbose:
|
|
743
|
+
_emit_verbose_guidance(ctx)
|
|
744
|
+
return
|
|
745
|
+
|
|
681
746
|
try:
|
|
682
747
|
client = get_client(ctx)
|
|
683
748
|
agent = _resolve_agent(
|
|
@@ -686,6 +751,7 @@ def run(
|
|
|
686
751
|
|
|
687
752
|
parsed_chat_history = _parse_chat_history(chat_history)
|
|
688
753
|
renderer, working_console = _setup_run_renderer(ctx, save, verbose)
|
|
754
|
+
_maybe_attach_transcript_toggle(ctx, renderer)
|
|
689
755
|
|
|
690
756
|
try:
|
|
691
757
|
client.timeout = float(timeout)
|
|
@@ -703,8 +769,29 @@ def run(
|
|
|
703
769
|
|
|
704
770
|
result = client.agents.run_agent(**run_kwargs, timeout=timeout)
|
|
705
771
|
|
|
772
|
+
slash_mode = _running_in_slash_mode(ctx)
|
|
773
|
+
agent_id = str(_safe_agent_attribute(agent, "id") or "") or None
|
|
774
|
+
agent_name = _safe_agent_attribute(agent, "name")
|
|
775
|
+
model_hint = _get_agent_model_name(agent)
|
|
776
|
+
|
|
777
|
+
transcript_context = store_transcript_for_session(
|
|
778
|
+
ctx,
|
|
779
|
+
renderer,
|
|
780
|
+
final_result=result,
|
|
781
|
+
agent_id=agent_id,
|
|
782
|
+
agent_name=agent_name,
|
|
783
|
+
model=model_hint,
|
|
784
|
+
source="slash" if slash_mode else "cli",
|
|
785
|
+
)
|
|
786
|
+
|
|
706
787
|
_handle_run_output(ctx, result, renderer)
|
|
707
788
|
_save_run_transcript(save, result, working_console)
|
|
789
|
+
maybe_launch_post_run_viewer(
|
|
790
|
+
ctx,
|
|
791
|
+
transcript_context,
|
|
792
|
+
console=console,
|
|
793
|
+
slash_mode=slash_mode,
|
|
794
|
+
)
|
|
708
795
|
|
|
709
796
|
except AgentTimeoutError as e:
|
|
710
797
|
error_msg = str(e)
|
|
@@ -714,6 +801,25 @@ def run(
|
|
|
714
801
|
_handle_command_exception(ctx, e)
|
|
715
802
|
|
|
716
803
|
|
|
804
|
+
def _running_in_slash_mode(ctx: Any) -> bool:
|
|
805
|
+
ctx_obj = getattr(ctx, "obj", None)
|
|
806
|
+
return isinstance(ctx_obj, dict) and bool(ctx_obj.get("_slash_session"))
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
def _emit_verbose_guidance(ctx: Any) -> None:
|
|
810
|
+
if _running_in_slash_mode(ctx):
|
|
811
|
+
message = (
|
|
812
|
+
"[dim]Tip:[/] Verbose streaming has been retired in the command palette. Run the agent normally and open "
|
|
813
|
+
"the post-run viewer (Ctrl+T) to inspect the transcript."
|
|
814
|
+
)
|
|
815
|
+
else:
|
|
816
|
+
message = (
|
|
817
|
+
"[dim]Tip:[/] `--verbose` is no longer supported. Re-run without the flag and toggle the post-run viewer "
|
|
818
|
+
"(Ctrl+T) for detailed output."
|
|
819
|
+
)
|
|
820
|
+
handle_rich_output(ctx, markup_text(message))
|
|
821
|
+
|
|
822
|
+
|
|
717
823
|
def _handle_import_file_logic(
|
|
718
824
|
import_file: str,
|
|
719
825
|
model: str | None,
|
|
@@ -1317,7 +1423,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1317
1423
|
handle_rich_output(
|
|
1318
1424
|
ctx,
|
|
1319
1425
|
markup_text(
|
|
1320
|
-
f"[
|
|
1426
|
+
f"[{SUCCESS_STYLE}]✅ Successfully synced {success_count} LangFlow agents ({total_count} total processed)[/]"
|
|
1321
1427
|
),
|
|
1322
1428
|
)
|
|
1323
1429
|
|