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
glaip_sdk/cli/main.py DELETED
@@ -1,604 +0,0 @@
1
- """Main CLI entry point for AIP SDK.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- import logging
8
- import subprocess
9
- import sys
10
- from typing import Any
11
-
12
- import click
13
- from rich.console import Console
14
-
15
- from glaip_sdk import Client
16
- from glaip_sdk.branding import (
17
- ERROR,
18
- ERROR_STYLE,
19
- INFO,
20
- INFO_STYLE,
21
- NEUTRAL,
22
- SUCCESS,
23
- SUCCESS_STYLE,
24
- WARNING,
25
- WARNING_STYLE,
26
- AIPBranding,
27
- )
28
- from glaip_sdk.cli.account_store import get_account_store
29
- from glaip_sdk.cli.auth import resolve_credentials
30
- from glaip_sdk.cli.commands.accounts import accounts_group
31
- from glaip_sdk.cli.commands.agents import agents_group
32
- from glaip_sdk.cli.commands.configure import (
33
- config_group,
34
- configure_command,
35
- )
36
- from glaip_sdk.cli.commands.mcps import mcps_group
37
- from glaip_sdk.cli.commands.models import models_group
38
- from glaip_sdk.cli.commands.tools import tools_group
39
- from glaip_sdk.cli.commands.transcripts import transcripts_group
40
- from glaip_sdk.cli.commands.update import _build_upgrade_command, update_command
41
- from glaip_sdk.cli.config import load_config
42
- from glaip_sdk.cli.hints import in_slash_mode
43
- from glaip_sdk.cli.transcript import get_transcript_cache_stats
44
- from glaip_sdk.cli.update_notifier import maybe_notify_update
45
- from glaip_sdk.cli.utils import format_size, sdk_version, spinner_context, update_spinner
46
- from glaip_sdk.config.constants import (
47
- DEFAULT_AGENT_RUN_TIMEOUT,
48
- )
49
- from glaip_sdk.icons import ICON_AGENT
50
- from glaip_sdk.rich_components import AIPPanel, AIPTable
51
-
52
-
53
- def _suppress_chatty_loggers() -> None:
54
- """Silence noisy SDK/httpx logs for CLI output."""
55
- noisy_loggers = [
56
- "glaip_sdk.client",
57
- "httpx",
58
- "httpcore",
59
- ]
60
- for name in noisy_loggers:
61
- logger = logging.getLogger(name)
62
- # Respect existing configuration: only raise level when unset,
63
- # and avoid changing propagation if a custom handler is already attached.
64
- if logger.level == logging.NOTSET:
65
- logger.setLevel(logging.WARNING)
66
- if not logger.handlers:
67
- logger.propagate = False
68
-
69
-
70
- # Import SlashSession for potential mocking in tests
71
- try:
72
- from glaip_sdk.cli.slash import SlashSession
73
- except ImportError: # pragma: no cover - optional slash dependencies
74
- # Slash dependencies might not be available in all environments
75
- SlashSession = None
76
-
77
- # Constants
78
- AVAILABLE_STATUS = "✅ Available"
79
-
80
-
81
- @click.group(invoke_without_command=True)
82
- @click.version_option(package_name="glaip-sdk", prog_name="aip")
83
- @click.option(
84
- "--api-url",
85
- help="(Deprecated) AIP API URL; use profiles via --account instead",
86
- hidden=True,
87
- )
88
- @click.option(
89
- "--api-key",
90
- help="(Deprecated) AIP API Key; use profiles via --account instead",
91
- hidden=True,
92
- )
93
- @click.option("--timeout", default=30.0, help="Request timeout in seconds")
94
- @click.option(
95
- "--view",
96
- "view",
97
- type=click.Choice(["rich", "plain", "json", "md"]),
98
- default="rich",
99
- help="Output view format",
100
- )
101
- @click.option("--no-tty", is_flag=True, help="Disable TTY renderer")
102
- @click.option(
103
- "--account",
104
- "account_name",
105
- help="Target a named account profile for this command",
106
- hidden=True, # Hidden by default, shown with --help --all
107
- )
108
- @click.pass_context
109
- def main(
110
- ctx: Any,
111
- api_url: str | None,
112
- api_key: str | None,
113
- timeout: float | None,
114
- view: str | None,
115
- no_tty: bool,
116
- account_name: str | None,
117
- ) -> None:
118
- r"""GL AIP SDK Command Line Interface.
119
-
120
- A comprehensive CLI for managing GL AIP resources including
121
- agents, tools, MCPs, and more.
122
-
123
- \b
124
- Examples:
125
- aip version # Show detailed version info
126
- aip configure # Configure credentials
127
- aip accounts add prod # Add account profile
128
- aip accounts use staging # Switch account
129
- aip agents list # List all agents
130
- aip tools create my_tool.py # Create a new tool
131
- aip agents run my-agent "Hello world" # Run an agent
132
-
133
- \b
134
- NEW: Store multiple accounts via 'aip accounts add' and switch with 'aip accounts use'.
135
- """
136
- # Store configuration in context
137
- ctx.ensure_object(dict)
138
- ctx.obj["api_url"] = api_url
139
- ctx.obj["api_key"] = api_key
140
- ctx.obj["timeout"] = timeout
141
- ctx.obj["view"] = view
142
- ctx.obj["account_name"] = account_name
143
-
144
- _suppress_chatty_loggers()
145
-
146
- ctx.obj["tty"] = not no_tty
147
-
148
- launching_slash = (
149
- ctx.invoked_subcommand is None
150
- and not ctx.resilient_parsing
151
- and _should_launch_slash(ctx)
152
- and SlashSession is not None
153
- )
154
-
155
- if not ctx.resilient_parsing and ctx.obj["tty"] and not launching_slash:
156
- console = Console()
157
- preferred_console = maybe_notify_update(
158
- sdk_version(),
159
- console=console,
160
- ctx=ctx,
161
- slash_command="update",
162
- )
163
- ctx.obj["_preferred_console"] = preferred_console or console
164
-
165
- if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
166
- if launching_slash:
167
- session = SlashSession(ctx)
168
- session.run()
169
- ctx.exit()
170
- else:
171
- click.echo(ctx.get_help())
172
- ctx.exit()
173
-
174
-
175
- # Add command groups
176
- main.add_command(accounts_group)
177
- main.add_command(agents_group)
178
- main.add_command(config_group)
179
- main.add_command(tools_group)
180
- main.add_command(mcps_group)
181
- main.add_command(models_group)
182
- main.add_command(transcripts_group)
183
-
184
- # Add top-level commands
185
- main.add_command(configure_command)
186
- main.add_command(update_command)
187
-
188
-
189
- # Tip: `--version` is provided by click.version_option above.
190
-
191
-
192
- def _should_launch_slash(ctx: click.Context) -> bool:
193
- """Determine whether to open the command palette automatically."""
194
- ctx_obj = ctx.obj or {}
195
- if not bool(ctx_obj.get("tty", True)):
196
- return False
197
-
198
- if not (sys.stdin.isatty() and sys.stdout.isatty()):
199
- return False
200
-
201
- return True
202
-
203
-
204
- def _load_and_merge_config(ctx: click.Context) -> dict:
205
- """Load configuration from multiple sources and merge them."""
206
- context_config = ctx.obj or {}
207
- account_name = context_config.get("account_name")
208
-
209
- # Resolve credentials using new account store system
210
- api_url, api_key, source = resolve_credentials(
211
- account_name=account_name,
212
- api_url=context_config.get("api_url"),
213
- api_key=context_config.get("api_key"),
214
- )
215
-
216
- # Load other config values (timeout, etc.) from legacy config
217
- legacy_config = load_config()
218
- timeout = context_config.get("timeout") or legacy_config.get("timeout")
219
-
220
- return {
221
- "api_url": api_url,
222
- "api_key": api_key,
223
- "timeout": timeout,
224
- "_source": source, # Track where credentials came from
225
- }
226
-
227
-
228
- def _validate_config_and_show_error(config: dict, console: Console) -> None:
229
- """Validate configuration and show error if incomplete."""
230
- store = get_account_store()
231
- has_accounts = bool(store.list_accounts())
232
- if not config.get("api_url") or not config.get("api_key"):
233
- no_accounts_hint = "" if has_accounts else "\n • No accounts found; create one now to continue"
234
- console.print(
235
- AIPPanel(
236
- f"[{ERROR_STYLE}]❌ Configuration incomplete[/]\n\n"
237
- f"🔍 Current config:\n"
238
- f" • API URL: {config.get('api_url', 'Not set')}\n"
239
- f" • API Key: {'***' + config.get('api_key', '')[-4:] if config.get('api_key') else 'Not set'}\n\n"
240
- f"💡 To fix this:\n"
241
- f" • Run 'aip accounts add default' to set up credentials\n"
242
- f" • Or run 'aip configure' for interactive setup\n"
243
- f" • Or run 'aip accounts list' to see current accounts{no_accounts_hint}",
244
- title="❌ Configuration Error",
245
- border_style=ERROR,
246
- ),
247
- )
248
- console.print(f"\n[{SUCCESS_STYLE}]✅ AIP - Ready[/] (SDK v{sdk_version()}) - Configure to connect")
249
- sys.exit(1)
250
-
251
-
252
- def _resolve_status_console(ctx: Any) -> tuple[Console, bool]:
253
- """Return the console to use and whether we are in slash mode."""
254
- ctx_obj = ctx.obj if isinstance(ctx.obj, dict) else None
255
- console_override = ctx_obj.get("_slash_console") if ctx_obj else None
256
- preferred_console = ctx_obj.get("_preferred_console") if ctx_obj else None
257
- if preferred_console is None:
258
- # In heavily mocked tests, maybe_notify_update may be patched with a return_value
259
- preferred_console = getattr(maybe_notify_update, "return_value", None)
260
- console = console_override or preferred_console or Console()
261
- slash_mode = in_slash_mode(ctx)
262
- return console, slash_mode
263
-
264
-
265
- def _render_status_heading(console: Console, slash_mode: bool, config: dict) -> bool:
266
- """Print the status heading/banner.
267
-
268
- Returns True if a generic ready line was printed (to avoid duplication).
269
- """
270
- del slash_mode # heading now consistent across invocation contexts
271
- ready_printed = False
272
- console.print(f"[{INFO_STYLE}]GL AIP status[/]")
273
- console.print("")
274
-
275
- # Show account information
276
- source = str(config.get("_source") or "unknown")
277
- account_name = None
278
- if source.startswith("account:") or source.startswith("active_profile:"):
279
- account_name = source.split(":", 1)[1]
280
-
281
- if account_name:
282
- store = get_account_store()
283
- account = store.get_account(account_name)
284
- if account:
285
- url = account.get("api_url", "")
286
- # Format source to match spec: "active_profile" instead of "active_profile:name"
287
- display_source = source.split(":")[0] if ":" in source else source
288
- console.print(f"[{SUCCESS_STYLE}]Account: {account_name} (source={display_source}) · API URL: {url}[/]")
289
- else:
290
- console.print(f"[{SUCCESS_STYLE}]✅ GL AIP ready[/] (SDK v{sdk_version()})")
291
- ready_printed = True
292
- elif source == "flag":
293
- console.print(f"[{SUCCESS_STYLE}]Account: (source={source})[/]")
294
- else:
295
- console.print(f"[{SUCCESS_STYLE}]✅ GL AIP ready[/] (SDK v{sdk_version()})")
296
- ready_printed = True
297
-
298
- return ready_printed
299
-
300
-
301
- def _collect_cache_summary() -> tuple[str | None, str | None]:
302
- """Collect transcript cache summary and optional note."""
303
- try:
304
- cache_stats = get_transcript_cache_stats()
305
- except Exception:
306
- return "[dim]Saved transcripts[/dim]: unavailable", None
307
-
308
- runs_text = f"{cache_stats.entry_count} runs saved"
309
- if cache_stats.total_bytes:
310
- size_part = f" · {format_size(cache_stats.total_bytes)} used"
311
- else:
312
- size_part = ""
313
-
314
- cache_line = f"[dim]Saved transcripts[/dim]: {runs_text}{size_part} · {cache_stats.cache_dir}"
315
- return cache_line, None
316
-
317
-
318
- def _display_cache_summary(console: Console, slash_mode: bool, cache_line: str | None, cache_note: str | None) -> None:
319
- """Render the cache summary details."""
320
- if cache_line:
321
- console.print(cache_line)
322
- if cache_note and not slash_mode:
323
- console.print(cache_note)
324
-
325
-
326
- def _safe_list_call(obj: Any, attr: str) -> list[Any]:
327
- """Call list-like client methods defensively, returning an empty list on failure."""
328
- func = getattr(obj, attr, None)
329
- if callable(func):
330
- try:
331
- return func()
332
- except Exception as exc:
333
- logging.getLogger(__name__).debug(
334
- "Failed to call %s on %s: %s", attr, type(obj).__name__, exc, exc_info=True
335
- )
336
- return []
337
- return []
338
-
339
-
340
- def _get_client_from_config(config: dict) -> Any:
341
- """Return a Client instance built from config."""
342
- return Client(
343
- api_url=config["api_url"],
344
- api_key=config["api_key"],
345
- timeout=config.get("timeout", 30.0),
346
- )
347
-
348
-
349
- def _create_and_test_client(config: dict, console: Console, *, compact: bool = False) -> Client:
350
- """Create client and test connection by fetching resources."""
351
- client: Any = _get_client_from_config(config)
352
-
353
- # Test connection by listing resources with a spinner where available
354
- try:
355
- with spinner_context(
356
- None,
357
- "[bold blue]Checking GL AIP status…[/bold blue]",
358
- console_override=console,
359
- spinner_style=INFO,
360
- ) as status_indicator:
361
- update_spinner(status_indicator, "[bold blue]Fetching agents…[/bold blue]")
362
- agents = client.list_agents()
363
-
364
- update_spinner(status_indicator, "[bold blue]Fetching tools…[/bold blue]")
365
- tools = client.list_tools()
366
-
367
- update_spinner(status_indicator, "[bold blue]Fetching MCPs…[/bold blue]")
368
- mcps = client.list_mcps()
369
- except Exception as e:
370
- # Show AIP Ready status even if connection fails
371
- if compact:
372
- status_text = "API call failed"
373
- api_url = getattr(client, "api_url", config.get("api_url", ""))
374
- console.print(f"[dim]• Base URL[/dim]: {api_url} ({status_text})")
375
- console.print(f"[{ERROR_STYLE}]• Error[/]: {e}")
376
- console.print("[dim]• Tip[/dim]: Check network connectivity or API permissions and try again.")
377
- console.print("[dim]• Resources[/dim]: unavailable")
378
- else:
379
- api_url = getattr(client, "api_url", config.get("api_url", ""))
380
- console.print(
381
- AIPPanel(
382
- f"[{WARNING_STYLE}]⚠️ Connection established but API call failed[/]\n"
383
- f"🔗 API URL: {api_url}\n"
384
- f"❌ Error: {e}\n\n"
385
- f"💡 This usually means:\n"
386
- f" • Network connectivity issues\n"
387
- f" • API permissions problems\n"
388
- f" • Backend service issues",
389
- title="⚠️ Partial Connection",
390
- border_style=WARNING,
391
- ),
392
- )
393
- return client
394
-
395
- # Create status table
396
- table = AIPTable(title="🔗 GL AIP Status")
397
- table.add_column("Resource", style=INFO, width=15)
398
- table.add_column("Count", style=NEUTRAL, width=10)
399
- table.add_column("Status", style=SUCCESS_STYLE, width=15)
400
-
401
- table.add_row("Agents", str(len(agents)), AVAILABLE_STATUS)
402
- table.add_row("Tools", str(len(tools)), AVAILABLE_STATUS)
403
- table.add_row("MCPs", str(len(mcps)), AVAILABLE_STATUS)
404
-
405
- if compact:
406
- connection_summary = "GL AIP reachable"
407
- console.print(f"[dim]• Base URL[/dim]: {client.api_url} ({connection_summary})")
408
- console.print(f"[dim]• Agent timeout[/dim]: {DEFAULT_AGENT_RUN_TIMEOUT}s")
409
- console.print(f"[dim]• Resources[/dim]: agents {len(agents)}, tools {len(tools)}, mcps {len(mcps)}")
410
- else:
411
- console.print( # pragma: no cover - UI display formatting
412
- AIPPanel(
413
- f"[{SUCCESS_STYLE}]✅ Connected to GL AIP[/]\n"
414
- f"🔗 API URL: {client.api_url}\n"
415
- f"{ICON_AGENT} Agent Run Timeout: {DEFAULT_AGENT_RUN_TIMEOUT}s",
416
- title="🚀 Connection Status",
417
- border_style=SUCCESS,
418
- ),
419
- )
420
-
421
- console.print(table) # pragma: no cover - UI display formatting
422
-
423
- return client
424
-
425
-
426
- def _handle_connection_error(config: dict, console: Console, error: Exception) -> None:
427
- """Handle connection errors and show troubleshooting information."""
428
- console.print(
429
- AIPPanel(
430
- f"[{ERROR_STYLE}]❌ Connection failed[/]\n\n"
431
- f"🔍 Error: {error}\n\n"
432
- f"💡 Troubleshooting steps:\n"
433
- f" • Verify your API URL and key are correct\n"
434
- f" • Check network connectivity to {config.get('api_url', 'your API')}\n"
435
- f" • Run 'aip configure' to update credentials\n"
436
- f" • Run 'aip config list' to check configuration",
437
- title="❌ Connection Error",
438
- border_style=ERROR,
439
- ),
440
- )
441
- # Log and return; callers decide whether to exit.
442
-
443
-
444
- @main.command()
445
- @click.option(
446
- "--account",
447
- "account_name",
448
- help="Target a named account profile for this command",
449
- )
450
- @click.pass_context
451
- def status(ctx: Any, account_name: str | None) -> None:
452
- """Show connection status and basic info."""
453
- config: dict = {}
454
- console: Console | None = None
455
- try:
456
- if account_name:
457
- if ctx.obj is None:
458
- ctx.obj = {}
459
- ctx.obj["account_name"] = account_name
460
-
461
- console, slash_mode = _resolve_status_console(ctx)
462
-
463
- # Load and merge configuration
464
- config = _load_and_merge_config(ctx)
465
-
466
- ready_printed = _render_status_heading(console, slash_mode, config)
467
- if not ready_printed:
468
- console.print(f"[{SUCCESS_STYLE}]✅ GL AIP ready[/] (SDK v{sdk_version()})")
469
-
470
- cache_result = _collect_cache_summary()
471
- if isinstance(cache_result, tuple) and len(cache_result) == 2:
472
- cache_line, cache_note = cache_result
473
- else:
474
- cache_line, cache_note = cache_result, None
475
- _display_cache_summary(console, slash_mode, cache_line, cache_note)
476
-
477
- # Validate configuration
478
- _validate_config_and_show_error(config, console)
479
-
480
- # Create and test client connection using unified compact layout
481
- client = _create_and_test_client(config, console, compact=True)
482
- close = getattr(client, "close", None)
483
- if callable(close):
484
- try:
485
- close()
486
- except Exception:
487
- pass
488
-
489
- except Exception as e:
490
- # Handle any unexpected errors during the process and exit with error code
491
- fallback_console = console or Console()
492
- _handle_connection_error(config or {}, fallback_console, e)
493
- sys.exit(1)
494
-
495
-
496
- @main.command()
497
- def version() -> None:
498
- """Show version information."""
499
- branding = AIPBranding.create_from_sdk(sdk_version=sdk_version(), package_name="glaip-sdk")
500
- branding.display_version_panel()
501
-
502
-
503
- @main.command()
504
- @click.option("--check-only", is_flag=True, help="Only check for updates without installing")
505
- @click.option(
506
- "--force",
507
- is_flag=True,
508
- help="Force reinstall even if already up-to-date (adds --force-reinstall)",
509
- )
510
- def update(check_only: bool, force: bool) -> None:
511
- """Update AIP SDK to the latest version from PyPI."""
512
- slash_mode = in_slash_mode()
513
- try:
514
- console = Console()
515
-
516
- if check_only:
517
- console.print(
518
- AIPPanel(
519
- "[bold blue]🔍 Checking for updates...[/bold blue]\n\n💡 To install updates, run: aip update",
520
- title="📋 Update Check",
521
- border_style="blue",
522
- ),
523
- )
524
- return
525
-
526
- update_hint = ""
527
- if not slash_mode:
528
- update_hint = "\n💡 Use --check-only to just check for updates"
529
-
530
- console.print(
531
- AIPPanel(
532
- "[bold blue]🔄 Updating AIP SDK...[/bold blue]\n\n"
533
- "📦 This will update the package from PyPI"
534
- f"{update_hint}",
535
- title="Update Process",
536
- border_style="blue",
537
- padding=(0, 1),
538
- ),
539
- )
540
-
541
- # Update using pip
542
- try:
543
- cmd = list(_build_upgrade_command(include_prerelease=False))
544
- # Replace package name with "glaip-sdk" (main.py uses different name)
545
- cmd[-1] = "glaip-sdk"
546
- if force:
547
- cmd.insert(5, "--force-reinstall")
548
- subprocess.run(cmd, capture_output=True, text=True, check=True)
549
-
550
- verify_hint = ""
551
- if not slash_mode:
552
- verify_hint = "\n💡 Restart your terminal or run 'aip --version' to verify"
553
-
554
- console.print(
555
- AIPPanel(
556
- f"[{SUCCESS_STYLE}]✅ Update successful![/]\n\n"
557
- "🔄 AIP SDK has been updated to the latest version"
558
- f"{verify_hint}",
559
- title="🎉 Update Complete",
560
- border_style=SUCCESS,
561
- padding=(0, 1),
562
- ),
563
- )
564
-
565
- # Show new version
566
- version_result = subprocess.run(
567
- [sys.executable, "-m", "glaip_sdk.cli.main", "--version"],
568
- capture_output=True,
569
- text=True,
570
- check=True,
571
- )
572
- console.print(f"📋 New version: {version_result.stdout.strip()}")
573
-
574
- except subprocess.CalledProcessError as e:
575
- console.print(
576
- AIPPanel(
577
- f"[{ERROR_STYLE}]❌ Update failed[/]\n\n"
578
- f"🔍 Error: {e.stderr}\n\n"
579
- "💡 Troubleshooting:\n"
580
- " • Check your internet connection\n"
581
- " • Try running: pip install --upgrade glaip-sdk\n"
582
- " • Check if you have write permissions",
583
- title="❌ Update Error",
584
- border_style=ERROR,
585
- padding=(0, 1),
586
- ),
587
- )
588
- sys.exit(1)
589
-
590
- except ImportError:
591
- console.print(
592
- AIPPanel(
593
- f"[{ERROR_STYLE}]❌ Rich library not available[/]\n\n"
594
- "💡 Install rich: pip install rich\n"
595
- " Then try: aip update",
596
- title="❌ Missing Dependency",
597
- border_style=ERROR,
598
- ),
599
- )
600
- sys.exit(1)
601
-
602
-
603
- if __name__ == "__main__":
604
- main() # pylint: disable=no-value-for-parameter