glaip-sdk 0.6.12__py3-none-any.whl → 0.6.14__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.
Files changed (156) hide show
  1. glaip_sdk/__init__.py +42 -5
  2. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/METADATA +31 -37
  3. glaip_sdk-0.6.14.dist-info/RECORD +12 -0
  4. {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/WHEEL +2 -1
  5. glaip_sdk-0.6.14.dist-info/entry_points.txt +2 -0
  6. glaip_sdk-0.6.14.dist-info/top_level.txt +1 -0
  7. glaip_sdk/agents/__init__.py +0 -27
  8. glaip_sdk/agents/base.py +0 -1191
  9. glaip_sdk/cli/__init__.py +0 -9
  10. glaip_sdk/cli/account_store.py +0 -540
  11. glaip_sdk/cli/agent_config.py +0 -78
  12. glaip_sdk/cli/auth.py +0 -699
  13. glaip_sdk/cli/commands/__init__.py +0 -5
  14. glaip_sdk/cli/commands/accounts.py +0 -746
  15. glaip_sdk/cli/commands/agents.py +0 -1509
  16. glaip_sdk/cli/commands/common_config.py +0 -101
  17. glaip_sdk/cli/commands/configure.py +0 -896
  18. glaip_sdk/cli/commands/mcps.py +0 -1356
  19. glaip_sdk/cli/commands/models.py +0 -69
  20. glaip_sdk/cli/commands/tools.py +0 -576
  21. glaip_sdk/cli/commands/transcripts.py +0 -755
  22. glaip_sdk/cli/commands/update.py +0 -61
  23. glaip_sdk/cli/config.py +0 -95
  24. glaip_sdk/cli/constants.py +0 -38
  25. glaip_sdk/cli/context.py +0 -150
  26. glaip_sdk/cli/core/__init__.py +0 -79
  27. glaip_sdk/cli/core/context.py +0 -124
  28. glaip_sdk/cli/core/output.py +0 -846
  29. glaip_sdk/cli/core/prompting.py +0 -649
  30. glaip_sdk/cli/core/rendering.py +0 -187
  31. glaip_sdk/cli/display.py +0 -355
  32. glaip_sdk/cli/hints.py +0 -57
  33. glaip_sdk/cli/io.py +0 -112
  34. glaip_sdk/cli/main.py +0 -604
  35. glaip_sdk/cli/masking.py +0 -136
  36. glaip_sdk/cli/mcp_validators.py +0 -287
  37. glaip_sdk/cli/pager.py +0 -266
  38. glaip_sdk/cli/parsers/__init__.py +0 -7
  39. glaip_sdk/cli/parsers/json_input.py +0 -177
  40. glaip_sdk/cli/resolution.py +0 -67
  41. glaip_sdk/cli/rich_helpers.py +0 -27
  42. glaip_sdk/cli/slash/__init__.py +0 -15
  43. glaip_sdk/cli/slash/accounts_controller.py +0 -578
  44. glaip_sdk/cli/slash/accounts_shared.py +0 -75
  45. glaip_sdk/cli/slash/agent_session.py +0 -285
  46. glaip_sdk/cli/slash/prompt.py +0 -256
  47. glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
  48. glaip_sdk/cli/slash/session.py +0 -1708
  49. glaip_sdk/cli/slash/tui/__init__.py +0 -9
  50. glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
  51. glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
  52. glaip_sdk/cli/slash/tui/loading.py +0 -58
  53. glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
  54. glaip_sdk/cli/transcript/__init__.py +0 -31
  55. glaip_sdk/cli/transcript/cache.py +0 -536
  56. glaip_sdk/cli/transcript/capture.py +0 -329
  57. glaip_sdk/cli/transcript/export.py +0 -38
  58. glaip_sdk/cli/transcript/history.py +0 -815
  59. glaip_sdk/cli/transcript/launcher.py +0 -77
  60. glaip_sdk/cli/transcript/viewer.py +0 -374
  61. glaip_sdk/cli/update_notifier.py +0 -290
  62. glaip_sdk/cli/utils.py +0 -263
  63. glaip_sdk/cli/validators.py +0 -238
  64. glaip_sdk/client/__init__.py +0 -11
  65. glaip_sdk/client/_agent_payloads.py +0 -520
  66. glaip_sdk/client/agent_runs.py +0 -147
  67. glaip_sdk/client/agents.py +0 -1335
  68. glaip_sdk/client/base.py +0 -502
  69. glaip_sdk/client/main.py +0 -249
  70. glaip_sdk/client/mcps.py +0 -370
  71. glaip_sdk/client/run_rendering.py +0 -700
  72. glaip_sdk/client/shared.py +0 -21
  73. glaip_sdk/client/tools.py +0 -661
  74. glaip_sdk/client/validators.py +0 -198
  75. glaip_sdk/config/constants.py +0 -52
  76. glaip_sdk/mcps/__init__.py +0 -21
  77. glaip_sdk/mcps/base.py +0 -345
  78. glaip_sdk/models/__init__.py +0 -90
  79. glaip_sdk/models/agent.py +0 -47
  80. glaip_sdk/models/agent_runs.py +0 -116
  81. glaip_sdk/models/common.py +0 -42
  82. glaip_sdk/models/mcp.py +0 -33
  83. glaip_sdk/models/tool.py +0 -33
  84. glaip_sdk/payload_schemas/__init__.py +0 -7
  85. glaip_sdk/payload_schemas/agent.py +0 -85
  86. glaip_sdk/registry/__init__.py +0 -55
  87. glaip_sdk/registry/agent.py +0 -164
  88. glaip_sdk/registry/base.py +0 -139
  89. glaip_sdk/registry/mcp.py +0 -253
  90. glaip_sdk/registry/tool.py +0 -232
  91. glaip_sdk/runner/__init__.py +0 -59
  92. glaip_sdk/runner/base.py +0 -84
  93. glaip_sdk/runner/deps.py +0 -115
  94. glaip_sdk/runner/langgraph.py +0 -782
  95. glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
  96. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
  97. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
  98. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
  99. glaip_sdk/runner/tool_adapter/__init__.py +0 -18
  100. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
  101. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
  102. glaip_sdk/tools/__init__.py +0 -22
  103. glaip_sdk/tools/base.py +0 -435
  104. glaip_sdk/utils/__init__.py +0 -86
  105. glaip_sdk/utils/a2a/__init__.py +0 -34
  106. glaip_sdk/utils/a2a/event_processor.py +0 -188
  107. glaip_sdk/utils/agent_config.py +0 -194
  108. glaip_sdk/utils/bundler.py +0 -267
  109. glaip_sdk/utils/client.py +0 -111
  110. glaip_sdk/utils/client_utils.py +0 -486
  111. glaip_sdk/utils/datetime_helpers.py +0 -58
  112. glaip_sdk/utils/discovery.py +0 -78
  113. glaip_sdk/utils/display.py +0 -135
  114. glaip_sdk/utils/export.py +0 -143
  115. glaip_sdk/utils/general.py +0 -61
  116. glaip_sdk/utils/import_export.py +0 -168
  117. glaip_sdk/utils/import_resolver.py +0 -492
  118. glaip_sdk/utils/instructions.py +0 -101
  119. glaip_sdk/utils/rendering/__init__.py +0 -115
  120. glaip_sdk/utils/rendering/formatting.py +0 -264
  121. glaip_sdk/utils/rendering/layout/__init__.py +0 -64
  122. glaip_sdk/utils/rendering/layout/panels.py +0 -156
  123. glaip_sdk/utils/rendering/layout/progress.py +0 -202
  124. glaip_sdk/utils/rendering/layout/summary.py +0 -74
  125. glaip_sdk/utils/rendering/layout/transcript.py +0 -606
  126. glaip_sdk/utils/rendering/models.py +0 -85
  127. glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
  128. glaip_sdk/utils/rendering/renderer/base.py +0 -1024
  129. glaip_sdk/utils/rendering/renderer/config.py +0 -27
  130. glaip_sdk/utils/rendering/renderer/console.py +0 -55
  131. glaip_sdk/utils/rendering/renderer/debug.py +0 -178
  132. glaip_sdk/utils/rendering/renderer/factory.py +0 -138
  133. glaip_sdk/utils/rendering/renderer/stream.py +0 -202
  134. glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
  135. glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
  136. glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
  137. glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
  138. glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
  139. glaip_sdk/utils/rendering/state.py +0 -204
  140. glaip_sdk/utils/rendering/step_tree_state.py +0 -100
  141. glaip_sdk/utils/rendering/steps/__init__.py +0 -34
  142. glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
  143. glaip_sdk/utils/rendering/steps/format.py +0 -176
  144. glaip_sdk/utils/rendering/steps/manager.py +0 -387
  145. glaip_sdk/utils/rendering/timing.py +0 -36
  146. glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
  147. glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
  148. glaip_sdk/utils/resource_refs.py +0 -195
  149. glaip_sdk/utils/run_renderer.py +0 -41
  150. glaip_sdk/utils/runtime_config.py +0 -425
  151. glaip_sdk/utils/serialization.py +0 -424
  152. glaip_sdk/utils/sync.py +0 -142
  153. glaip_sdk/utils/tool_detection.py +0 -33
  154. glaip_sdk/utils/validation.py +0 -264
  155. glaip_sdk-0.6.12.dist-info/RECORD +0 -159
  156. glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
@@ -1,187 +0,0 @@
1
- """CLI rendering utilities: Rich console helpers, viewer launchers, renderer builders.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import os
11
- import sys
12
- from contextlib import AbstractContextManager, contextmanager, nullcontext
13
- from typing import Any
14
-
15
- from rich.console import Console
16
-
17
- from glaip_sdk.branding import ACCENT_STYLE
18
- from glaip_sdk.cli.context import _get_view, get_ctx_value
19
- from glaip_sdk.utils.rendering.renderer import (
20
- CapturingConsole,
21
- RendererFactoryOptions,
22
- RichStreamRenderer,
23
- make_default_renderer,
24
- make_verbose_renderer,
25
- )
26
-
27
- # Export console for backward compatibility
28
- console = Console()
29
-
30
-
31
- def _can_use_spinner(ctx: Any | None, active_console: Console) -> bool:
32
- """Check if spinner output is allowed in the current environment."""
33
- if ctx is not None:
34
- tty_enabled = bool(get_ctx_value(ctx, "tty", True))
35
- view = (_get_view(ctx) or "rich").lower()
36
- if not tty_enabled or view not in {"", "rich"}:
37
- return False
38
-
39
- if not active_console.is_terminal:
40
- return False
41
-
42
- return _stream_supports_tty(getattr(active_console, "file", None))
43
-
44
-
45
- def _stream_supports_tty(stream: Any) -> bool:
46
- """Return True if the provided stream can safely render a spinner."""
47
- target = stream if hasattr(stream, "isatty") else sys.stdout
48
- try:
49
- return bool(target.isatty())
50
- except Exception:
51
- return False
52
-
53
-
54
- def update_spinner(status_indicator: Any | None, message: str) -> None:
55
- """Update spinner text when a status indicator is active."""
56
- if status_indicator is None:
57
- return
58
-
59
- try:
60
- status_indicator.update(message)
61
- except Exception: # pragma: no cover - defensive update
62
- pass
63
-
64
-
65
- def stop_spinner(status_indicator: Any | None) -> None:
66
- """Stop an active spinner safely."""
67
- if status_indicator is None:
68
- return
69
-
70
- try:
71
- status_indicator.stop()
72
- except Exception: # pragma: no cover - defensive stop
73
- pass
74
-
75
-
76
- # Backwards compatibility aliases for legacy callers
77
- _spinner_update = update_spinner
78
- _spinner_stop = stop_spinner
79
-
80
-
81
- def spinner_context(
82
- ctx: Any | None,
83
- message: str,
84
- *,
85
- console_override: Console | None = None,
86
- spinner: str = "dots",
87
- spinner_style: str = ACCENT_STYLE,
88
- ) -> AbstractContextManager[Any]:
89
- """Return a context manager that renders a spinner when appropriate."""
90
- active_console = console_override or console
91
- if not _can_use_spinner(ctx, active_console):
92
- return nullcontext()
93
-
94
- status = active_console.status(
95
- message,
96
- spinner=spinner,
97
- spinner_style=spinner_style,
98
- )
99
-
100
- if not hasattr(status, "__enter__") or not hasattr(status, "__exit__"):
101
- return nullcontext()
102
-
103
- return status
104
-
105
-
106
- def _register_renderer_with_session(ctx: Any, renderer: RichStreamRenderer) -> None:
107
- """Attach renderer to an active slash session when present."""
108
- try:
109
- ctx_obj = getattr(ctx, "obj", None)
110
- session = ctx_obj.get("_slash_session") if isinstance(ctx_obj, dict) else None
111
- if session and hasattr(session, "register_active_renderer"):
112
- session.register_active_renderer(renderer)
113
- except Exception:
114
- # Never let session bookkeeping break renderer creation
115
- pass
116
-
117
-
118
- def build_renderer(
119
- _ctx: Any,
120
- *,
121
- save_path: str | os.PathLike[str] | None,
122
- verbose: bool = False,
123
- _tty_enabled: bool = True,
124
- live: bool | None = None,
125
- snapshots: bool | None = None,
126
- ) -> tuple[RichStreamRenderer, Console | CapturingConsole]:
127
- """Build renderer and capturing console for CLI commands.
128
-
129
- Args:
130
- _ctx: Click context object for CLI operations.
131
- save_path: Path to save output to (enables capturing console).
132
- verbose: Whether to enable verbose mode.
133
- _tty_enabled: Whether TTY is available for interactive features.
134
- live: Whether to enable live rendering mode (overrides verbose default).
135
- snapshots: Whether to capture and store snapshots.
136
-
137
- Returns:
138
- Tuple of (renderer, capturing_console) for streaming output.
139
- """
140
- # Use capturing console if saving output
141
- working_console = CapturingConsole(console, capture=True) if save_path else console
142
-
143
- # Configure renderer based on verbose mode and explicit overrides
144
- live_enabled = bool(live) if live is not None else not verbose
145
- cfg_overrides = {
146
- "live": live_enabled,
147
- "append_finished_snapshots": bool(snapshots) if snapshots is not None else False,
148
- }
149
- renderer_console = (
150
- working_console.original_console if isinstance(working_console, CapturingConsole) else working_console
151
- )
152
- factory = make_verbose_renderer if verbose else make_default_renderer
153
- factory_options = RendererFactoryOptions(
154
- console=renderer_console,
155
- cfg_overrides=cfg_overrides,
156
- verbose=verbose if factory is make_default_renderer else None,
157
- )
158
- renderer = factory_options.build(factory)
159
-
160
- # Link the renderer back to the slash session when running from the palette.
161
- _register_renderer_with_session(_ctx, renderer)
162
-
163
- return renderer, working_console
164
-
165
-
166
- @contextmanager
167
- def with_client_and_spinner(
168
- ctx: Any,
169
- spinner_message: str,
170
- *,
171
- console_override: Console | None = None,
172
- ) -> Any:
173
- """Context manager for commands that need client and spinner.
174
-
175
- Args:
176
- ctx: Click context.
177
- spinner_message: Message to display in spinner.
178
- console_override: Optional console override.
179
-
180
- Yields:
181
- Client instance.
182
- """
183
- from glaip_sdk.cli.core.context import get_client # noqa: PLC0415
184
-
185
- client = get_client(ctx)
186
- with spinner_context(ctx, spinner_message, console_override=console_override):
187
- yield client
glaip_sdk/cli/display.py DELETED
@@ -1,355 +0,0 @@
1
- """CLI display utilities for success/failure panels and Rich renderers.
2
-
3
- This module handles all display-related functionality for CLI commands,
4
- including success messages, error handling, and output formatting.
5
-
6
- Authors:
7
- Raymond Christopher (raymond.christopher@gdplabs.id)
8
- """
9
-
10
- import json
11
- from typing import Any
12
-
13
- import click
14
- from rich.console import Console
15
- from rich.panel import Panel
16
- from rich.text import Text
17
-
18
- from glaip_sdk.branding import ERROR_STYLE, SUCCESS, SUCCESS_STYLE, WARNING_STYLE
19
- from glaip_sdk.cli.hints import command_hint, format_command_hint, in_slash_mode
20
- from glaip_sdk.cli.rich_helpers import markup_text
21
- from glaip_sdk.icons import ICON_AGENT, ICON_TOOL
22
- from glaip_sdk.rich_components import AIPPanel
23
-
24
- console = Console()
25
-
26
-
27
- def display_creation_success(
28
- resource_type: str, resource_name: str, resource_id: str, **additional_fields: Any
29
- ) -> Panel:
30
- """Create standardized success message for resource creation.
31
-
32
- Args:
33
- resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
34
- resource_name: Name of the created resource
35
- resource_id: ID of the created resource
36
- **additional_fields: Additional fields to display
37
-
38
- Returns:
39
- Rich Panel object for display
40
- """
41
- # Build additional fields display
42
- fields_display = ""
43
- if additional_fields:
44
- fields_display = "\n" + "\n".join(f"{key}: {value}" for key, value in additional_fields.items())
45
-
46
- return AIPPanel(
47
- f"[{SUCCESS_STYLE}]✅ {resource_type} '{resource_name}' created successfully![/]\n\n"
48
- f"ID: {resource_id}{fields_display}",
49
- title=f"{ICON_AGENT} {resource_type} Created",
50
- border_style=SUCCESS,
51
- padding=(0, 1),
52
- )
53
-
54
-
55
- def display_update_success(resource_type: str, resource_name: str) -> Text:
56
- """Create standardized success message for resource update.
57
-
58
- Args:
59
- resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
60
- resource_name: Name of the updated resource
61
-
62
- Returns:
63
- Rich Text object for display
64
- """
65
- return markup_text(f"[{SUCCESS_STYLE}]✅ {resource_type} '{resource_name}' updated successfully[/]")
66
-
67
-
68
- def display_deletion_success(resource_type: str, resource_name: str) -> Text:
69
- """Create standardized success message for resource deletion.
70
-
71
- Args:
72
- resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
73
- resource_name: Name of the deleted resource
74
-
75
- Returns:
76
- Rich Text object for display
77
- """
78
- return markup_text(f"[{SUCCESS_STYLE}]✅ {resource_type} '{resource_name}' deleted successfully[/]")
79
-
80
-
81
- def display_api_error(error: Exception, operation: str = "operation") -> None:
82
- """Display standardized API error message.
83
-
84
- Args:
85
- error: The exception that occurred
86
- operation: Description of the operation that failed
87
- """
88
- error_type = type(error).__name__
89
- error_message = markup_text(f"[{ERROR_STYLE}]Error during {operation}: {error}[/]")
90
- error_message.no_wrap = True
91
- error_message.overflow = "ignore"
92
- console.print(error_message)
93
-
94
- error_type_message = markup_text(f"[dim]Error type: {error_type}[/dim]")
95
- error_type_message.no_wrap = True
96
- error_type_message.overflow = "ignore"
97
- console.print(error_type_message)
98
-
99
-
100
- def print_api_error(e: Exception) -> None:
101
- """Print API error with consistent formatting for both JSON and Rich views.
102
-
103
- Args:
104
- e: The exception to format and display
105
-
106
- Notes:
107
- - Extracts status_code, error_type, and payload from APIError exceptions
108
- - Provides consistent error reporting across CLI commands
109
- - Handles both JSON and Rich output formats
110
- - Special handling for validation errors with detailed field-level errors
111
- """
112
- if not hasattr(e, "__dict__"):
113
- console.print(f"[{ERROR_STYLE}]Error: {e}[/]")
114
- return
115
-
116
- if not hasattr(e, "status_code"):
117
- console.print(f"[{ERROR_STYLE}]Error: {e}[/]")
118
- return
119
-
120
- error_text = str(e).strip()
121
- if not error_text:
122
- error_text = "Unknown error"
123
- if "\n" in error_text:
124
- error_text = error_text.splitlines()[0]
125
- console.print(f"[{ERROR_STYLE}]API Error: {error_text}[/]")
126
- status_code = getattr(e, "status_code", None)
127
- if status_code is not None:
128
- console.print(f"[{WARNING_STYLE}]Status: {status_code}[/]")
129
-
130
- payload = getattr(e, "payload", _MISSING)
131
- if payload is _MISSING:
132
- return
133
-
134
- if payload:
135
- if not _print_structured_payload(payload):
136
- console.print(f"[{WARNING_STYLE}]Details: {payload}[/]")
137
- else:
138
- console.print(f"[{WARNING_STYLE}]Details: {payload}[/]")
139
-
140
-
141
- def _print_structured_payload(payload: Any) -> bool:
142
- """Print structured payloads with enhanced formatting. Returns True if handled."""
143
- if not isinstance(payload, dict):
144
- return False
145
-
146
- if "detail" in payload and _print_validation_details(payload["detail"]):
147
- return True
148
-
149
- if "details" in payload and _print_details_field(payload["details"]):
150
- return True
151
-
152
- return False
153
-
154
-
155
- def _print_validation_details(detail: Any) -> bool:
156
- """Render FastAPI-style validation errors."""
157
- if not isinstance(detail, list) or not detail:
158
- return False
159
-
160
- console.print(f"[{ERROR_STYLE}]Validation Errors:[/]")
161
- for error in detail:
162
- if isinstance(error, dict):
163
- loc = " -> ".join(str(x) for x in error.get("loc", []))
164
- msg = error.get("msg", "Unknown error")
165
- error_type = error.get("type", "unknown")
166
- location = loc if loc else "field"
167
- console.print(f" [{WARNING_STYLE}]• {location}:[/] {msg}")
168
- if error_type != "unknown":
169
- console.print(f" [dim]({error_type})[/dim]")
170
- else:
171
- console.print(f" [{WARNING_STYLE}]•[/] {error}")
172
- return True
173
-
174
-
175
- def _print_details_field(details: Any) -> bool:
176
- """Render custom error details from API payloads."""
177
- if not details:
178
- return False
179
-
180
- console.print(f"[{ERROR_STYLE}]Error Details:[/]")
181
- if isinstance(details, str):
182
- console.print(f" [{WARNING_STYLE}]•[/] {details}")
183
- elif isinstance(details, list):
184
- for detail in details:
185
- console.print(f" [{WARNING_STYLE}]•[/] {detail}")
186
- else:
187
- console.print(f" [{WARNING_STYLE}]•[/] {details}")
188
- return True
189
-
190
-
191
- _MISSING = object()
192
-
193
-
194
- def build_resource_result_data(resource: Any, fields: list[str]) -> dict[str, Any]:
195
- """Return a normalized mapping of ``fields`` extracted from ``resource``."""
196
- result: dict[str, Any] = {}
197
- for field in fields:
198
- try:
199
- value = getattr(resource, field)
200
- except AttributeError:
201
- value = _MISSING
202
- except Exception:
203
- value = _MISSING
204
-
205
- result[field] = _normalise_field_value(field, value)
206
-
207
- return result
208
-
209
-
210
- def _normalise_field_value(field: str, value: Any) -> Any:
211
- """Convert special sentinel values into display-friendly text."""
212
- if value is _MISSING:
213
- return "N/A"
214
- if hasattr(value, "_mock_name"):
215
- return "N/A"
216
- if field == "id":
217
- return str(value)
218
- return value
219
-
220
-
221
- def _get_context_object(ctx: Any) -> dict[str, Any]:
222
- """Get context object safely."""
223
- ctx_obj = getattr(ctx, "obj", {}) if ctx is not None else {}
224
- return ctx_obj if isinstance(ctx_obj, dict) else {}
225
-
226
-
227
- def _should_output_json(ctx_obj: dict[str, Any]) -> bool:
228
- """Check if output should be in JSON format."""
229
- return ctx_obj.get("view") == "json"
230
-
231
-
232
- def _build_error_output_data(error: Exception) -> dict[str, Any]:
233
- """Build error output data with additional error details."""
234
- output_data = {"error": str(error)}
235
-
236
- # Add additional error details if available
237
- if hasattr(error, "status_code"):
238
- output_data["status_code"] = error.status_code
239
- if hasattr(error, "error_type"):
240
- output_data["error_type"] = error.error_type
241
- if hasattr(error, "payload"):
242
- output_data["details"] = error.payload
243
-
244
- return output_data
245
-
246
-
247
- def _build_success_output_data(data: Any) -> dict[str, Any]:
248
- """Build success output data."""
249
- return data if data is not None else {"success": True}
250
-
251
-
252
- def handle_json_output(ctx: Any, data: Any = None, error: Exception = None) -> None:
253
- """Handle JSON output format for CLI commands.
254
-
255
- Args:
256
- ctx: Click context
257
- data: Data to output (for successful operations)
258
- error: Error to output (for failed operations)
259
- """
260
- ctx_obj = _get_context_object(ctx)
261
-
262
- if _should_output_json(ctx_obj):
263
- if error:
264
- output_data = _build_error_output_data(error)
265
- else:
266
- output_data = _build_success_output_data(data)
267
-
268
- click.echo(json.dumps(output_data, indent=2, default=str))
269
-
270
-
271
- def handle_rich_output(ctx: Any, rich_content: Any = None) -> None:
272
- """Handle Rich output format for CLI commands.
273
-
274
- Args:
275
- ctx: Click context
276
- rich_content: Rich content to display
277
- """
278
- ctx_obj = getattr(ctx, "obj", {}) if ctx is not None else {}
279
- if not isinstance(ctx_obj, dict):
280
- ctx_obj = {}
281
-
282
- if ctx_obj.get("view") != "json" and rich_content:
283
- console.print(rich_content)
284
-
285
-
286
- def display_confirmation_prompt(resource_type: str, resource_name: str) -> bool:
287
- """Display standardized confirmation prompt for destructive operations.
288
-
289
- Args:
290
- resource_type: Type of resource (e.g., "Agent", "Tool", "MCP")
291
- resource_name: Name of the resource
292
-
293
- Returns:
294
- True if user confirms, False otherwise
295
- """
296
- if not click.confirm(f"Are you sure you want to delete {resource_type.lower()} '{resource_name}'?"):
297
- if console.is_terminal:
298
- console.print(Text("Deletion cancelled."))
299
- return False
300
- return True
301
-
302
-
303
- def display_agent_run_suggestions(agent: Any) -> Panel:
304
- """Return a panel with post-creation suggestions for an agent."""
305
- agent_id = getattr(agent, "id", "")
306
- agent_name = getattr(agent, "name", "")
307
- slash_mode = in_slash_mode()
308
- run_hint_id = command_hint(
309
- f'agents run {agent_id} "Your message here"',
310
- slash_command=None,
311
- )
312
- run_hint_name = command_hint(
313
- f'agents run "{agent_name}" "Your message here"',
314
- slash_command=None,
315
- )
316
-
317
- content_parts: list[str] = ["[bold blue]💡 Next Steps:[/bold blue]\n\n"]
318
-
319
- if slash_mode:
320
- slash_shortcuts = "\n".join(
321
- f" {format_command_hint(command, description) or command}"
322
- for command, description in (
323
- ("/details", "Show configuration (toggle preview)"),
324
- ("/help", "Show command palette menu"),
325
- ("/exit", "Return to the palette"),
326
- )
327
- )
328
- content_parts.append(
329
- f"🚀 Start chatting with [bold]{agent_name}[/bold] right here:\n"
330
- f" Type your message below and press Enter to run it immediately.\n\n"
331
- f"{ICON_TOOL} Slash shortcuts:\n"
332
- f"{slash_shortcuts}"
333
- )
334
- else:
335
- cli_hint_lines = [format_command_hint(hint) or hint for hint in (run_hint_id, run_hint_name) if hint]
336
- if cli_hint_lines:
337
- joined_hints = "\n".join(f" {hint}" for hint in cli_hint_lines)
338
- content_parts.append(f"🚀 Run this agent from the CLI:\n{joined_hints}\n\n")
339
- content_parts.append(
340
- f"{ICON_TOOL} Available options:\n"
341
- f" [dim]--chat-history[/dim] Include previous conversation\n"
342
- f" [dim]--file[/dim] Attach files\n"
343
- f" [dim]--input[/dim] Alternative input method\n"
344
- f" [dim]--timeout[/dim] Set execution timeout\n"
345
- f" [dim]--save[/dim] Save transcript to file\n"
346
- f" [dim]--verbose[/dim] Show detailed execution\n\n"
347
- f"💡 [dim]Input text can be positional OR use --input flag (both work!)[/dim]"
348
- )
349
-
350
- return AIPPanel(
351
- "".join(content_parts),
352
- title=f"{ICON_AGENT} Ready to Run Agent",
353
- border_style="blue",
354
- padding=(0, 1),
355
- )
glaip_sdk/cli/hints.py DELETED
@@ -1,57 +0,0 @@
1
- """Helpers for formatting CLI/slash command hints.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import click
10
-
11
- from glaip_sdk.branding import HINT_COMMAND_STYLE, HINT_DESCRIPTION_COLOR
12
-
13
-
14
- def in_slash_mode(ctx: click.Context | None = None) -> bool:
15
- """Return True when running inside the slash command palette."""
16
- if ctx is None:
17
- try:
18
- ctx = click.get_current_context(silent=True)
19
- except RuntimeError:
20
- ctx = None
21
-
22
- if ctx is None:
23
- return False
24
-
25
- obj = getattr(ctx, "obj", None)
26
- if isinstance(obj, dict):
27
- return bool(obj.get("_slash_session"))
28
-
29
- return bool(getattr(obj, "_slash_session", False))
30
-
31
-
32
- def command_hint(
33
- cli_command: str | None,
34
- slash_command: str | None = None,
35
- *,
36
- ctx: click.Context | None = None,
37
- ) -> str | None:
38
- """Return the appropriate command string for the current mode."""
39
- if in_slash_mode(ctx):
40
- if not slash_command:
41
- return None
42
- return slash_command if slash_command.startswith("/") else f"/{slash_command}"
43
-
44
- if not cli_command:
45
- return None
46
- return f"aip {cli_command}"
47
-
48
-
49
- def format_command_hint(command: str | None, description: str | None = None) -> str | None:
50
- """Return a Rich markup string that highlights a command hint."""
51
- if not command:
52
- return None
53
-
54
- highlighted = f"[{HINT_COMMAND_STYLE}]{command}[/]"
55
- if description:
56
- highlighted += f" [{HINT_DESCRIPTION_COLOR}]{description}[/{HINT_DESCRIPTION_COLOR}]"
57
- return highlighted