glaip-sdk 0.7.4__py3-none-any.whl → 0.7.6__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.
@@ -156,7 +156,13 @@ def _build_manual_upgrade_command(
156
156
  is_flag=True,
157
157
  help="Include pre-release versions when upgrading.",
158
158
  )
159
- def update_command(include_prerelease: bool) -> None:
159
+ @click.option(
160
+ "--reinstall",
161
+ "force_reinstall",
162
+ is_flag=True,
163
+ help="Force reinstall even if already up-to-date.",
164
+ )
165
+ def update_command(include_prerelease: bool, force_reinstall: bool) -> None:
160
166
  """Upgrade the glaip-sdk package using pip or uv tool install."""
161
167
  console = Console()
162
168
  # Call _is_uv_managed_environment() once and pass explicitly to avoid redundant calls
@@ -164,12 +170,21 @@ def update_command(include_prerelease: bool) -> None:
164
170
  if not is_uv and not _is_pip_available():
165
171
  error_detail, troubleshooting = _build_missing_pip_guidance(
166
172
  include_prerelease=include_prerelease,
173
+ force_reinstall=force_reinstall,
167
174
  )
168
175
  raise click.ClickException(f"{error_detail}\n{troubleshooting}")
169
- upgrade_cmd = _build_upgrade_command(include_prerelease, is_uv=is_uv)
176
+ upgrade_cmd = _build_upgrade_command(
177
+ include_prerelease,
178
+ is_uv=is_uv,
179
+ force_reinstall=force_reinstall,
180
+ )
170
181
 
171
182
  # Determine the appropriate manual command for error messages
172
- manual_cmd = _build_manual_upgrade_command(include_prerelease, is_uv=is_uv)
183
+ manual_cmd = _build_manual_upgrade_command(
184
+ include_prerelease,
185
+ is_uv=is_uv,
186
+ force_reinstall=force_reinstall,
187
+ )
173
188
 
174
189
  console.print(f"[{ACCENT_STYLE}]Upgrading {PACKAGE_NAME} using[/] [{INFO_STYLE}]{' '.join(upgrade_cmd)}[/]")
175
190
 
@@ -43,6 +43,7 @@ PYPI_JSON_URL = "https://pypi.org/pypi/{package}/json"
43
43
  DEFAULT_TIMEOUT = 1.5 # seconds
44
44
 
45
45
  _LOGGER = logging.getLogger(__name__)
46
+ _UPDATE_VERSIONS_KEY = "_update_notifier_versions"
46
47
 
47
48
 
48
49
  def _parse_version(value: str) -> Version | None:
@@ -152,6 +153,7 @@ def maybe_notify_update(
152
153
  "- choose Update now or Skip to continue."
153
154
  )
154
155
  active_console.print(message)
156
+ _stash_update_versions(ctx, current_version, latest_version)
155
157
  _handle_update_decision(active_console, ctx)
156
158
  return
157
159
 
@@ -167,6 +169,7 @@ def maybe_notify_update(
167
169
  )
168
170
  active_console.print(panel)
169
171
  if should_prompt:
172
+ _stash_update_versions(ctx, current_version, latest_version)
170
173
  _handle_update_decision(active_console, ctx)
171
174
 
172
175
 
@@ -207,7 +210,13 @@ def _prompt_update_decision(console: Console) -> Literal["update", "skip"]:
207
210
 
208
211
  while True:
209
212
  try:
210
- response = console.input("Choice [1/2]: ").strip().lower()
213
+ raw_response = console.input("Choice [1/2]: ")
214
+ # Strip whitespace and convert to lowercase
215
+ response = raw_response.strip().lower()
216
+ # Remove any non-printable control characters (but keep printable chars)
217
+ # This handles cases where ANSI escape sequences or other control chars leak into input
218
+ response = "".join(char for char in response if char.isprintable() or char.isspace())
219
+ response = response.strip() # Strip again after filtering
211
220
  except (KeyboardInterrupt, EOFError):
212
221
  console.print(f"\n[{WARNING_STYLE}]Update skipped.[/]")
213
222
  return "skip"
@@ -305,7 +314,8 @@ def _run_update_command(console: Console, ctx: Any) -> None:
305
314
  manual_cmd = _get_manual_upgrade_command(is_uv=True)
306
315
  console.print(f"[{INFO_STYLE}]💡 Tip:[/] Try running manually:\n [{ACCENT_STYLE}]{manual_cmd}[/]")
307
316
  else:
308
- _refresh_installed_version(console, ctx)
317
+ new_version = _refresh_installed_version(console, ctx)
318
+ _maybe_retry_update(console, ctx, new_version, is_uv)
309
319
 
310
320
 
311
321
  @contextmanager
@@ -326,7 +336,7 @@ def _suppress_library_logging(
326
336
  logger.setLevel(previous_level)
327
337
 
328
338
 
329
- def _refresh_installed_version(console: Console, ctx: Any) -> None:
339
+ def _refresh_installed_version(console: Console, ctx: Any) -> str | None:
330
340
  """Reload runtime metadata after an in-process upgrade."""
331
341
  new_version: str | None = None
332
342
  branding_module: Any | None = None
@@ -350,12 +360,13 @@ def _refresh_installed_version(console: Console, ctx: Any) -> None:
350
360
  try:
351
361
  branding_cls = getattr(branding_module, "AIPBranding", None) if branding_module else None
352
362
  session.refresh_branding(new_version, branding_cls=branding_cls)
353
- return
363
+ return new_version
354
364
  except Exception as exc: # pragma: no cover - defensive guard
355
365
  _LOGGER.debug("Failed to refresh active slash session: %s", exc, exc_info=True)
356
366
 
357
367
  if new_version:
358
368
  console.print(f"[{SUCCESS_STYLE}]CLI now running glaip-sdk {new_version}.[/]")
369
+ return new_version
359
370
 
360
371
 
361
372
  def _get_slash_session(ctx: Any) -> Any | None:
@@ -366,4 +377,122 @@ def _get_slash_session(ctx: Any) -> Any | None:
366
377
  return None
367
378
 
368
379
 
380
+ def _stash_update_versions(ctx: Any | None, current_version: str, latest_version: str) -> None:
381
+ """Persist update versions in the Click context for post-update checks."""
382
+ if ctx is None:
383
+ return
384
+ ctx_obj = getattr(ctx, "obj", None)
385
+ if isinstance(ctx_obj, dict):
386
+ ctx_obj[_UPDATE_VERSIONS_KEY] = {"current": current_version, "latest": latest_version}
387
+
388
+
389
+ def _get_update_versions(ctx: Any | None) -> tuple[str | None, str | None]:
390
+ """Return current/latest versions captured during the update prompt."""
391
+ if ctx is None:
392
+ return None, None
393
+ ctx_obj = getattr(ctx, "obj", None)
394
+ if not isinstance(ctx_obj, dict):
395
+ return None, None
396
+ payload = ctx_obj.get(_UPDATE_VERSIONS_KEY)
397
+ if not isinstance(payload, dict):
398
+ return None, None
399
+ current = payload.get("current")
400
+ latest = payload.get("latest")
401
+ return (
402
+ current if isinstance(current, str) else None,
403
+ latest if isinstance(latest, str) else None,
404
+ )
405
+
406
+
407
+ def _should_retry_update(
408
+ ctx: Any,
409
+ console: Console,
410
+ new_version: str | None,
411
+ ) -> tuple[str, str, Version, Version, Version] | None:
412
+ """Check if update retry is needed and return parsed versions if so."""
413
+ if ctx is None or not hasattr(ctx, "invoke"):
414
+ return None
415
+ if not _should_prompt_for_action(console, ctx):
416
+ return None
417
+
418
+ current_version, latest_version = _get_update_versions(ctx)
419
+ if not current_version or not latest_version or not new_version:
420
+ return None
421
+
422
+ current = _parse_version(current_version)
423
+ latest = _parse_version(latest_version)
424
+ installed = _parse_version(new_version)
425
+ if current is None or latest is None or installed is None:
426
+ return None
427
+
428
+ if installed >= latest:
429
+ return None
430
+
431
+ # Note: installed > current case is handled in _maybe_retry_update()
432
+ # to allow warning message to be printed before returning
433
+
434
+ return current_version, latest_version, current, latest, installed
435
+
436
+
437
+ def _handle_reinstall_error(console: Console, exc: Exception, is_uv: bool) -> None:
438
+ """Handle errors during reinstall attempt."""
439
+ if isinstance(exc, click.ClickException):
440
+ exc.show()
441
+ console.print(f"[{ERROR_STYLE}]Reinstall attempt failed.[/]")
442
+ _show_error_guidance(console, is_uv)
443
+ elif isinstance(exc, click.Abort):
444
+ console.print(f"[{WARNING_STYLE}]Reinstall skipped by user.[/]")
445
+ else:
446
+ console.print(f"[{ERROR_STYLE}]Unexpected error while reinstalling: {exc}[/]")
447
+ if is_uv:
448
+ manual_cmd = _get_manual_upgrade_command(is_uv=True)
449
+ console.print(f"[{INFO_STYLE}]💡 Tip:[/] Try running manually:\n [{ACCENT_STYLE}]{manual_cmd}[/]")
450
+
451
+
452
+ def _check_final_version(
453
+ console: Console, new_version: str | None, latest_version: str, latest: Version, is_uv: bool
454
+ ) -> None:
455
+ """Check and report final version status after reinstall."""
456
+ installed = _parse_version(new_version) if isinstance(new_version, str) else None
457
+ if installed is None or installed < latest:
458
+ console.print(
459
+ f"[{WARNING_STYLE}]Still on {new_version}. Your package index may not have {latest_version} yet.[/]"
460
+ )
461
+ if is_uv:
462
+ console.print(
463
+ f"[{INFO_STYLE}]💡 Tip:[/] If you need PyPI immediately, set "
464
+ f"[{ACCENT_STYLE}]UV_INDEX_URL=https://pypi.org/simple[/]."
465
+ )
466
+
467
+
468
+ def _maybe_retry_update(
469
+ console: Console,
470
+ ctx: Any,
471
+ new_version: str | None,
472
+ is_uv: bool,
473
+ ) -> None:
474
+ """Retry once with reinstall when the update did not advance versions."""
475
+ versions = _should_retry_update(ctx, console, new_version)
476
+ if versions is None:
477
+ return
478
+
479
+ current_version, latest_version, current, latest, installed = versions
480
+ if installed > current:
481
+ console.print(f"[{WARNING_STYLE}]Update installed {new_version}, but {latest_version} is still available.[/]")
482
+ return
483
+
484
+ console.print(
485
+ f"[{WARNING_STYLE}]Update completed but version stayed at {new_version}. Retrying with reinstall...[/]"
486
+ )
487
+
488
+ try:
489
+ ctx.invoke(update_command, force_reinstall=True)
490
+ except Exception as exc:
491
+ _handle_reinstall_error(console, exc, is_uv)
492
+ return
493
+
494
+ new_version = _refresh_installed_version(console, ctx)
495
+ _check_final_version(console, new_version, latest_version, latest, is_uv)
496
+
497
+
369
498
  __all__ = ["maybe_notify_update"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glaip-sdk
3
- Version: 0.7.4
3
+ Version: 0.7.6
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,11 +20,11 @@ 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.18; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
23
+ Requires-Dist: aip-agents-binary[local]>=0.5.21; (python_version >= "3.11" and python_version < "3.13") and extra == "local"
24
24
  Provides-Extra: memory
25
- Requires-Dist: aip-agents-binary[memory]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
25
+ Requires-Dist: aip-agents-binary[memory]>=0.5.21; (python_version >= "3.11" and python_version < "3.13") and extra == "memory"
26
26
  Provides-Extra: privacy
27
- Requires-Dist: aip-agents-binary[privacy]>=0.5.18; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
27
+ Requires-Dist: aip-agents-binary[privacy]>=0.5.21; (python_version >= "3.11" and python_version < "3.13") and extra == "privacy"
28
28
  Provides-Extra: dev
29
29
  Requires-Dist: pytest>=7.0.0; extra == "dev"
30
30
  Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
@@ -23,7 +23,7 @@ glaip_sdk/cli/mcp_validators.py,sha256=cwbz7p_p7_9xVuuF96OBQOdmEgo5UObU6iWWQ2X03
23
23
  glaip_sdk/cli/pager.py,sha256=TmiMDNpUMuZju7QJ6A_ITqIoEf8Dhv8U6mTXx2Fga1k,7935
24
24
  glaip_sdk/cli/resolution.py,sha256=AGvv7kllLcuvk_jdaArJqH3lId4IDEXpHceRZwy14xY,2448
25
25
  glaip_sdk/cli/rich_helpers.py,sha256=kO47N8e506rxrN6Oc9mbAWN3Qb536oQPWZy1s9A616g,819
26
- glaip_sdk/cli/update_notifier.py,sha256=fO1xbSBF8cHukEN_FZDJuhDRqOYubB1CoPYOgvy9J7U,12898
26
+ glaip_sdk/cli/update_notifier.py,sha256=0zpWxr4nSyz0tiLWyC7EEO2deAnVmsRcVlMV79G2QMI,18049
27
27
  glaip_sdk/cli/validators.py,sha256=k4J2ACYJPF6UmWJfENt9OHWdp4RNArVxR3hoeqauO88,5629
28
28
  glaip_sdk/cli/commands/__init__.py,sha256=6Z3ASXDut0lAbUX_umBFtxPzzFyqoiZfVeTahThFu1A,219
29
29
  glaip_sdk/cli/commands/accounts.py,sha256=vUZYt5Ii-nWKJ1nXRU684NHILpPXj40Xfh4qN1tZsNc,24685
@@ -31,7 +31,7 @@ glaip_sdk/cli/commands/common_config.py,sha256=seZUw_3kV7GlDH31uYHnT_Khq6B3oEuO-
31
31
  glaip_sdk/cli/commands/configure.py,sha256=ZToy6LSQ3ulEBrB9YpuWiIAiOQ2XQ11MxPNtN3V1V_A,30273
32
32
  glaip_sdk/cli/commands/models.py,sha256=kZKqwv2uzfyz8n_7b0hYTT8waaVZMDzVoSXtRvWa9jk,2042
33
33
  glaip_sdk/cli/commands/transcripts_original.py,sha256=6KEAP_mMdoNgydpunxLjYl6QJIY-CJorwLTBSF3Cfuo,26416
34
- glaip_sdk/cli/commands/update.py,sha256=SMO_Hr9WEolqvpFhEXY3TboBLHBfXIvBvwovbONEs7Y,6329
34
+ glaip_sdk/cli/commands/update.py,sha256=QYz51JdYSbzbLVIH3-Q-qh5MIY4o-LtpbbfMwHYuExA,6658
35
35
  glaip_sdk/cli/commands/agents/__init__.py,sha256=V-tRAqMcY4amDygp16clkEfQS4Sqw0vOR4BzAGHzNg0,3436
36
36
  glaip_sdk/cli/commands/agents/_common.py,sha256=2Zg_LctV6CCyZVrXz3xFs6fDX624jVTDzv9VYHMq2JM,17812
37
37
  glaip_sdk/cli/commands/agents/create.py,sha256=8IFWXZJexspy1M2059CUygVd_xmXXg3JZtVUskVwHMI,4819
@@ -206,8 +206,8 @@ glaip_sdk/utils/rendering/steps/format.py,sha256=Chnq7OBaj8XMeBntSBxrX5zSmrYeGcO
206
206
  glaip_sdk/utils/rendering/steps/manager.py,sha256=BiBmTeQMQhjRMykgICXsXNYh1hGsss-fH9BIGVMWFi0,13194
207
207
  glaip_sdk/utils/rendering/viewer/__init__.py,sha256=XrxmE2cMAozqrzo1jtDFm8HqNtvDcYi2mAhXLXn5CjI,457
208
208
  glaip_sdk/utils/rendering/viewer/presenter.py,sha256=mlLMTjnyeyPVtsyrAbz1BJu9lFGQSlS-voZ-_Cuugv0,5725
209
- glaip_sdk-0.7.4.dist-info/METADATA,sha256=r36rVJdxsiV-fUHo3SRNf_pakOeHayQy1KyL3ZCqN-M,8365
210
- glaip_sdk-0.7.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
211
- glaip_sdk-0.7.4.dist-info/entry_points.txt,sha256=NkhO6FfgX9Zrjn63GuKphf-dLw7KNJvucAcXc7P3aMk,54
212
- glaip_sdk-0.7.4.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
213
- glaip_sdk-0.7.4.dist-info/RECORD,,
209
+ glaip_sdk-0.7.6.dist-info/METADATA,sha256=jGATytvWTrk-Fe3kv_N6mxfD0vkpmDCsO4odOnOzPPM,8365
210
+ glaip_sdk-0.7.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
211
+ glaip_sdk-0.7.6.dist-info/entry_points.txt,sha256=NkhO6FfgX9Zrjn63GuKphf-dLw7KNJvucAcXc7P3aMk,54
212
+ glaip_sdk-0.7.6.dist-info/top_level.txt,sha256=td7yXttiYX2s94-4wFhv-5KdT0rSZ-pnJRSire341hw,10
213
+ glaip_sdk-0.7.6.dist-info/RECORD,,