glaip-sdk 0.6.20__py3-none-any.whl → 0.6.21__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.
@@ -6,9 +6,12 @@ Author:
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import importlib.util
10
+ import os
9
11
  import subprocess
10
12
  import sys
11
13
  from collections.abc import Sequence
14
+ from pathlib import Path
12
15
 
13
16
  import click
14
17
  from rich.console import Console
@@ -21,11 +24,54 @@ PACKAGE_NAME = "glaip-sdk"
21
24
  def _is_uv_managed_environment() -> bool:
22
25
  """Check if running in a uv-managed tool environment.
23
26
 
24
- Uses a path-based heuristic that may need updates if uv changes its layout.
27
+ Uses a path-based heuristic against sys.executable, sys.prefix, and UV_TOOL_DIR
28
+ or UV_TOOL_BIN to detect a case-insensitive "uv/tools" segment. Update if uv
29
+ changes its layout.
25
30
  """
26
- executable = str(sys.executable)
27
- # Check for uv tool install paths: ~/.local/share/uv/tools/*/bin/python*
28
- return ".local/share/uv/tools" in executable or "/uv/tools/" in executable
31
+ if _has_uv_tool_path(sys.executable):
32
+ return True
33
+ if _has_uv_tool_path(sys.prefix):
34
+ return True
35
+ uv_tool_dir = os.environ.get("UV_TOOL_DIR") or os.environ.get("UV_TOOL_BIN")
36
+ if uv_tool_dir and _has_uv_tool_path(uv_tool_dir):
37
+ return True
38
+ return False
39
+
40
+
41
+ def _has_uv_tool_path(path: str) -> bool:
42
+ """Return True when a path contains a case-insensitive uv/tools segment."""
43
+ parts = [part.lower() for part in Path(path).parts]
44
+ for idx, part in enumerate(parts[:-1]):
45
+ if part == "uv" and parts[idx + 1] == "tools":
46
+ return True
47
+ return False
48
+
49
+
50
+ def _is_pip_available() -> bool:
51
+ """Return True when pip can be imported in the current interpreter."""
52
+ return importlib.util.find_spec("pip") is not None
53
+
54
+
55
+ def _build_missing_pip_guidance(
56
+ *,
57
+ include_prerelease: bool,
58
+ package_name: str = PACKAGE_NAME,
59
+ force_reinstall: bool = False,
60
+ ) -> tuple[str, str]:
61
+ """Return error and troubleshooting guidance when pip is unavailable."""
62
+ manual_cmd = _build_manual_upgrade_command(
63
+ include_prerelease,
64
+ package_name=package_name,
65
+ is_uv=True,
66
+ force_reinstall=force_reinstall,
67
+ )
68
+ error_detail = "pip is not available in this environment."
69
+ troubleshooting = (
70
+ "💡 Troubleshooting:\n"
71
+ f" • If you installed via uv tool, run: {manual_cmd}\n"
72
+ " • Otherwise install pip: python -m ensurepip"
73
+ )
74
+ return error_detail, troubleshooting
29
75
 
30
76
 
31
77
  def _build_command_parts(
@@ -115,6 +161,11 @@ def update_command(include_prerelease: bool) -> None:
115
161
  console = Console()
116
162
  # Call _is_uv_managed_environment() once and pass explicitly to avoid redundant calls
117
163
  is_uv = _is_uv_managed_environment()
164
+ if not is_uv and not _is_pip_available():
165
+ error_detail, troubleshooting = _build_missing_pip_guidance(
166
+ include_prerelease=include_prerelease,
167
+ )
168
+ raise click.ClickException(f"{error_detail}\n{troubleshooting}")
118
169
  upgrade_cmd = _build_upgrade_command(include_prerelease, is_uv=is_uv)
119
170
 
120
171
  # Determine the appropriate manual command for error messages
glaip_sdk/cli/main.py CHANGED
@@ -36,8 +36,10 @@ from glaip_sdk.cli.commands.models import models_group
36
36
  from glaip_sdk.cli.commands.tools import tools_group
37
37
  from glaip_sdk.cli.commands.transcripts import transcripts_group
38
38
  from glaip_sdk.cli.commands.update import (
39
+ _build_missing_pip_guidance,
39
40
  _build_manual_upgrade_command,
40
41
  _build_upgrade_command,
42
+ _is_pip_available,
41
43
  _is_uv_managed_environment,
42
44
  update_command,
43
45
  )
@@ -52,6 +54,9 @@ from glaip_sdk.config.constants import (
52
54
  from glaip_sdk.icons import ICON_AGENT
53
55
  from glaip_sdk.rich_components import AIPPanel, AIPTable
54
56
 
57
+ # Constants
58
+ UPDATE_ERROR_TITLE = "❌ Update Error"
59
+
55
60
  Client: type[Any] | None = None
56
61
 
57
62
 
@@ -557,6 +562,21 @@ def update(check_only: bool, force: bool) -> None:
557
562
  # Update using pip or uv tool install
558
563
  try:
559
564
  is_uv = _is_uv_managed_environment()
565
+ if not is_uv and not _is_pip_available():
566
+ error_detail, troubleshooting = _build_missing_pip_guidance(
567
+ include_prerelease=False,
568
+ package_name="glaip-sdk",
569
+ force_reinstall=force,
570
+ )
571
+ console.print(
572
+ AIPPanel(
573
+ f"[{ERROR_STYLE}]❌ Update failed[/]\n\n🔍 Error: {error_detail}\n\n{troubleshooting}",
574
+ title=UPDATE_ERROR_TITLE,
575
+ border_style=ERROR,
576
+ padding=(0, 1),
577
+ ),
578
+ )
579
+ sys.exit(1)
560
580
  cmd = list(
561
581
  _build_upgrade_command(
562
582
  include_prerelease=False,
@@ -609,7 +629,7 @@ def update(check_only: bool, force: bool) -> None:
609
629
  console.print(
610
630
  AIPPanel(
611
631
  f"[{ERROR_STYLE}]❌ Update failed[/]\n\n🔍 Error: {error_detail}\n\n{troubleshooting}",
612
- title="❌ Update Error",
632
+ title=UPDATE_ERROR_TITLE,
613
633
  border_style=ERROR,
614
634
  padding=(0, 1),
615
635
  ),
@@ -627,7 +647,7 @@ def update(check_only: bool, force: bool) -> None:
627
647
  console.print(
628
648
  AIPPanel(
629
649
  f"[{ERROR_STYLE}]❌ Update failed[/]\n\n🔍 Error: {e.stderr}\n\n{troubleshooting}",
630
- title="❌ Update Error",
650
+ title=UPDATE_ERROR_TITLE,
631
651
  border_style=ERROR,
632
652
  padding=(0, 1),
633
653
  ),
@@ -27,6 +27,8 @@ from glaip_sdk.branding import (
27
27
  WARNING_STYLE,
28
28
  )
29
29
  from glaip_sdk.cli.commands.update import (
30
+ PACKAGE_NAME,
31
+ _build_command_parts,
30
32
  _build_manual_upgrade_command,
31
33
  _is_uv_managed_environment,
32
34
  update_command,
@@ -219,27 +221,90 @@ def _prompt_update_decision(console: Console) -> Literal["update", "skip"]:
219
221
  console.print(f"[{ERROR_STYLE}]Please enter 1 to update now or 2 to skip.[/]")
220
222
 
221
223
 
224
+ def _get_manual_upgrade_command(is_uv: bool) -> str:
225
+ """Get the manual upgrade command for the given environment type.
226
+
227
+ Args:
228
+ is_uv: True if running in uv tool environment, False for pip environment.
229
+
230
+ Returns:
231
+ Manual upgrade command string.
232
+ """
233
+ try:
234
+ return _build_manual_upgrade_command(include_prerelease=False, is_uv=is_uv)
235
+ except Exception:
236
+ # Fallback: rebuild from shared command parts to avoid hardcoded strings.
237
+ try:
238
+ command_parts, _ = _build_command_parts(
239
+ package_name=PACKAGE_NAME,
240
+ is_uv=is_uv,
241
+ force_reinstall=False,
242
+ include_prerelease=False,
243
+ )
244
+ except Exception:
245
+ command_parts = (
246
+ ["uv", "tool", "install", "--upgrade", PACKAGE_NAME]
247
+ if is_uv
248
+ else ["pip", "install", "--upgrade", PACKAGE_NAME]
249
+ )
250
+ return " ".join(command_parts)
251
+
252
+
253
+ def _show_proactive_uv_guidance(console: Console, is_uv: bool) -> None:
254
+ """Show proactive guidance for uv environments before update attempt.
255
+
256
+ Args:
257
+ console: Rich console for output.
258
+ is_uv: True if running in uv tool environment.
259
+ """
260
+ if not is_uv:
261
+ return
262
+
263
+ manual_cmd = _get_manual_upgrade_command(is_uv=True)
264
+ console.print(
265
+ f"[{INFO_STYLE}]💡 Detected uv tool environment.[/] "
266
+ f"If automatic update fails, run: [{ACCENT_STYLE}]{manual_cmd}[/]"
267
+ )
268
+
269
+
270
+ def _show_error_guidance(console: Console, is_uv: bool) -> None:
271
+ """Show error guidance with correct manual command based on environment.
272
+
273
+ Args:
274
+ console: Rich console for output.
275
+ is_uv: True if running in uv tool environment.
276
+ """
277
+ try:
278
+ manual_cmd = _get_manual_upgrade_command(is_uv=is_uv)
279
+ console.print(f"[{INFO_STYLE}]💡 Tip:[/] Run this command manually:\n [{ACCENT_STYLE}]{manual_cmd}[/]")
280
+ except Exception as exc: # pragma: no cover - defensive guard
281
+ _LOGGER.debug("Failed to render update tip: %s", exc, exc_info=True)
282
+
283
+
222
284
  def _run_update_command(console: Console, ctx: Any) -> None:
223
285
  """Invoke the built-in update command and surface any errors."""
286
+ # Detect uv environment proactively before attempting update
287
+ is_uv = _is_uv_managed_environment()
288
+
289
+ # Provide proactive guidance for uv environments
290
+ # This helps users on older versions (e.g., 0.6.19) that don't have uv detection
291
+ # in their update command
292
+ _show_proactive_uv_guidance(console, is_uv)
293
+
224
294
  try:
225
295
  ctx.invoke(update_command)
226
296
  except click.ClickException as exc:
227
297
  exc.show()
228
298
  console.print(f"[{ERROR_STYLE}]Update command exited with an error.[/]")
229
- # Provide additional context for uv environments
230
- try:
231
- if _is_uv_managed_environment():
232
- manual_cmd = _build_manual_upgrade_command(include_prerelease=False, is_uv=True)
233
- console.print(
234
- f"[{INFO_STYLE}]💡 Tip:[/] If automatic update failed, try running manually:\n"
235
- f" [{ACCENT_STYLE}]{manual_cmd}[/]"
236
- )
237
- except Exception as exc: # pragma: no cover - defensive guard
238
- _LOGGER.debug("Failed to render uv update tip: %s", exc, exc_info=True)
299
+ _show_error_guidance(console, is_uv)
239
300
  except click.Abort:
240
301
  console.print(f"[{WARNING_STYLE}]Update aborted by user.[/]")
241
302
  except Exception as exc: # pragma: no cover - defensive guard
242
303
  console.print(f"[{ERROR_STYLE}]Unexpected error while running update: {exc}[/]")
304
+ # Also provide guidance for unexpected errors in uv environments
305
+ if is_uv:
306
+ manual_cmd = _get_manual_upgrade_command(is_uv=True)
307
+ console.print(f"[{INFO_STYLE}]💡 Tip:[/] Try running manually:\n [{ACCENT_STYLE}]{manual_cmd}[/]")
243
308
  else:
244
309
  _refresh_installed_version(console, ctx)
245
310
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glaip-sdk
3
- Version: 0.6.20
3
+ Version: 0.6.21
4
4
  Summary: Python SDK and CLI for GL AIP (GDP Labs AI Agent Package) - Build, run, and manage AI agents
5
5
  Author-email: Raymond Christopher <raymond.christopher@gdplabs.id>
6
6
  License: MIT
@@ -20,12 +20,12 @@ Requires-Dist: gllm-core-binary>=0.1.0
20
20
  Requires-Dist: langchain-core>=0.3.0
21
21
  Requires-Dist: gllm-tools-binary>=0.1.3
22
22
  Provides-Extra: local
23
- Requires-Dist: aip-agents-binary[local]>=0.5.14; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
23
+ Requires-Dist: aip-agents-binary[local]>=0.5.16; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
24
24
  Requires-Dist: wrapt>=1.17.0; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
25
25
  Provides-Extra: memory
26
- Requires-Dist: aip-agents-binary[memory]>=0.5.14; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
26
+ Requires-Dist: aip-agents-binary[memory]>=0.5.16; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
27
27
  Provides-Extra: privacy
28
- Requires-Dist: aip-agents-binary[privacy]>=0.5.14; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
28
+ Requires-Dist: aip-agents-binary[privacy]>=0.5.16; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
29
29
  Requires-Dist: en-core-web-sm; extra == "privacy"
30
30
  Provides-Extra: dev
31
31
  Requires-Dist: pytest>=7.0.0; extra == "dev"
@@ -16,13 +16,13 @@ glaip_sdk/cli/context.py,sha256=--Y5vc6lgoAV7cRoUAr9UxSQaLmkMg29FolA7EwoRqM,3803
16
16
  glaip_sdk/cli/display.py,sha256=ojgWdGeD5KUnGOmWNqqK4JP-1EaWHWX--DWze3BmIz0,12137
17
17
  glaip_sdk/cli/hints.py,sha256=ca4krG103IS43s5BSLr0-N7uRMpte1_LY4nAXVvgDxo,1596
18
18
  glaip_sdk/cli/io.py,sha256=ChP6CRKbtuENsNomNEaMDfPDU0iqO-WuVvl4_y7F2io,3871
19
- glaip_sdk/cli/main.py,sha256=vQ8YcsFT4tG0xXCsJdS1WEWHK6ojiQS6pWIRWiW9PnA,23275
19
+ glaip_sdk/cli/main.py,sha256=NRmFZTPayDJGZMHy2TF9BXj2CQWpTEfg2SWj_4zSdUc,24047
20
20
  glaip_sdk/cli/masking.py,sha256=2lrXQ-pfL7N-vNEQRT1s4Xq3JPDPDT8RC61OdaTtkkc,4060
21
21
  glaip_sdk/cli/mcp_validators.py,sha256=cwbz7p_p7_9xVuuF96OBQOdmEgo5UObU6iWWQ2X03PI,10047
22
22
  glaip_sdk/cli/pager.py,sha256=XygkAB6UW3bte7I4KmK7-PUGCJiq2Pv-4-MfyXAmXCw,7925
23
23
  glaip_sdk/cli/resolution.py,sha256=K-VaEHm9SYY_qfb9538VNHykL4_2N6F8iQqI1zMx_64,2402
24
24
  glaip_sdk/cli/rich_helpers.py,sha256=kO47N8e506rxrN6Oc9mbAWN3Qb536oQPWZy1s9A616g,819
25
- glaip_sdk/cli/update_notifier.py,sha256=Wbe_6WD_iQKq1GvoFS_vdcD_PIfj1LGCXMf0on2jKMY,10732
25
+ glaip_sdk/cli/update_notifier.py,sha256=XtAZbIpO-h0bHUNHN0a4rvnt0mn4ckOX3dwOejN8chs,12929
26
26
  glaip_sdk/cli/utils.py,sha256=iemmKkpPndoZFBasoVqV7QArplchtr08yYWLA2efMzg,11996
27
27
  glaip_sdk/cli/validators.py,sha256=d-kq4y7HWMo6Gc7wLXWUsCt8JwFvJX_roZqRm1Nko1I,5622
28
28
  glaip_sdk/cli/commands/__init__.py,sha256=6Z3ASXDut0lAbUX_umBFtxPzzFyqoiZfVeTahThFu1A,219
@@ -34,7 +34,7 @@ glaip_sdk/cli/commands/mcps.py,sha256=tttqQnfM89iI9Pm94u8YRhiHMQNYNouecFX0brsT4c
34
34
  glaip_sdk/cli/commands/models.py,sha256=vfcGprK5CHprQ0CNpNzQlNNTELvdgKC7JxTG_ijOwmE,2009
35
35
  glaip_sdk/cli/commands/tools.py,sha256=_VBqG-vIjnn-gqvDlSTvcU7_F4N3ANGGKEECcQVR-BM,18430
36
36
  glaip_sdk/cli/commands/transcripts.py,sha256=ofxZLus1xLB061NxrLo1J6LPEb2VIxJTjmz7hLKgPmc,26377
37
- glaip_sdk/cli/commands/update.py,sha256=BZJ_E0iF0K9n6EupQAqjTSzUP4GPmq5ybqhx5i-_xQ0,4611
37
+ glaip_sdk/cli/commands/update.py,sha256=SMO_Hr9WEolqvpFhEXY3TboBLHBfXIvBvwovbONEs7Y,6329
38
38
  glaip_sdk/cli/core/__init__.py,sha256=HTQqpijKNts6bYnwY97rpP3J324phoQmGFi6OXqi0E4,2116
39
39
  glaip_sdk/cli/core/context.py,sha256=I22z5IhZ09g5FPtMycDGU9Aj20Qv3TOQLhA5enaU2qk,3970
40
40
  glaip_sdk/cli/core/output.py,sha256=hj5F1M_rEqr4CChmdyW1QzGiWL0Mwzf-BFw-d6pjhjY,28304
@@ -156,8 +156,8 @@ glaip_sdk/utils/rendering/steps/format.py,sha256=Chnq7OBaj8XMeBntSBxrX5zSmrYeGcO
156
156
  glaip_sdk/utils/rendering/steps/manager.py,sha256=BiBmTeQMQhjRMykgICXsXNYh1hGsss-fH9BIGVMWFi0,13194
157
157
  glaip_sdk/utils/rendering/viewer/__init__.py,sha256=XrxmE2cMAozqrzo1jtDFm8HqNtvDcYi2mAhXLXn5CjI,457
158
158
  glaip_sdk/utils/rendering/viewer/presenter.py,sha256=mlLMTjnyeyPVtsyrAbz1BJu9lFGQSlS-voZ-_Cuugv0,5725
159
- glaip_sdk-0.6.20.dist-info/METADATA,sha256=m7NqyPGjDfUjM7TCsH_KcD_NSlQKW3-BesUIpYdEq5g,8455
160
- glaip_sdk-0.6.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
161
- glaip_sdk-0.6.20.dist-info/entry_points.txt,sha256=65vNPUggyYnVGhuw7RhNJ8Fp2jygTcX0yxJBcBY3iLU,48
162
- glaip_sdk-0.6.20.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
163
- glaip_sdk-0.6.20.dist-info/RECORD,,
159
+ glaip_sdk-0.6.21.dist-info/METADATA,sha256=67DVFObOYjE67Eq16lYSj-qVo7OOq89SWbb7FdXYDbw,8455
160
+ glaip_sdk-0.6.21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
161
+ glaip_sdk-0.6.21.dist-info/entry_points.txt,sha256=65vNPUggyYnVGhuw7RhNJ8Fp2jygTcX0yxJBcBY3iLU,48
162
+ glaip_sdk-0.6.21.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
163
+ glaip_sdk-0.6.21.dist-info/RECORD,,