glaip-sdk 0.0.20__py3-none-any.whl → 0.1.3__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 (66) hide show
  1. glaip_sdk/_version.py +1 -3
  2. glaip_sdk/branding.py +2 -6
  3. glaip_sdk/cli/agent_config.py +2 -6
  4. glaip_sdk/cli/auth.py +11 -30
  5. glaip_sdk/cli/commands/agents.py +64 -107
  6. glaip_sdk/cli/commands/configure.py +12 -36
  7. glaip_sdk/cli/commands/mcps.py +25 -63
  8. glaip_sdk/cli/commands/models.py +2 -4
  9. glaip_sdk/cli/commands/tools.py +22 -35
  10. glaip_sdk/cli/commands/update.py +3 -8
  11. glaip_sdk/cli/config.py +1 -3
  12. glaip_sdk/cli/display.py +10 -13
  13. glaip_sdk/cli/io.py +8 -14
  14. glaip_sdk/cli/main.py +10 -30
  15. glaip_sdk/cli/mcp_validators.py +5 -15
  16. glaip_sdk/cli/pager.py +3 -9
  17. glaip_sdk/cli/parsers/json_input.py +11 -22
  18. glaip_sdk/cli/resolution.py +3 -9
  19. glaip_sdk/cli/rich_helpers.py +1 -3
  20. glaip_sdk/cli/slash/agent_session.py +5 -10
  21. glaip_sdk/cli/slash/prompt.py +3 -10
  22. glaip_sdk/cli/slash/session.py +46 -98
  23. glaip_sdk/cli/transcript/cache.py +6 -19
  24. glaip_sdk/cli/transcript/capture.py +45 -20
  25. glaip_sdk/cli/transcript/launcher.py +1 -3
  26. glaip_sdk/cli/transcript/viewer.py +224 -47
  27. glaip_sdk/cli/update_notifier.py +165 -21
  28. glaip_sdk/cli/utils.py +33 -91
  29. glaip_sdk/cli/validators.py +11 -12
  30. glaip_sdk/client/_agent_payloads.py +10 -30
  31. glaip_sdk/client/agents.py +33 -63
  32. glaip_sdk/client/base.py +77 -35
  33. glaip_sdk/client/mcps.py +1 -3
  34. glaip_sdk/client/run_rendering.py +121 -26
  35. glaip_sdk/client/tools.py +8 -24
  36. glaip_sdk/client/validators.py +20 -48
  37. glaip_sdk/exceptions.py +1 -3
  38. glaip_sdk/icons.py +9 -3
  39. glaip_sdk/models.py +14 -33
  40. glaip_sdk/payload_schemas/agent.py +1 -3
  41. glaip_sdk/utils/agent_config.py +4 -14
  42. glaip_sdk/utils/client_utils.py +7 -21
  43. glaip_sdk/utils/display.py +2 -6
  44. glaip_sdk/utils/general.py +1 -3
  45. glaip_sdk/utils/import_export.py +3 -9
  46. glaip_sdk/utils/rendering/formatting.py +52 -12
  47. glaip_sdk/utils/rendering/models.py +17 -8
  48. glaip_sdk/utils/rendering/renderer/__init__.py +1 -5
  49. glaip_sdk/utils/rendering/renderer/base.py +1181 -328
  50. glaip_sdk/utils/rendering/renderer/config.py +4 -10
  51. glaip_sdk/utils/rendering/renderer/debug.py +4 -14
  52. glaip_sdk/utils/rendering/renderer/panels.py +1 -3
  53. glaip_sdk/utils/rendering/renderer/progress.py +3 -11
  54. glaip_sdk/utils/rendering/renderer/stream.py +9 -42
  55. glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
  56. glaip_sdk/utils/rendering/renderer/toggle.py +182 -0
  57. glaip_sdk/utils/rendering/step_tree_state.py +100 -0
  58. glaip_sdk/utils/rendering/steps.py +899 -25
  59. glaip_sdk/utils/resource_refs.py +4 -13
  60. glaip_sdk/utils/serialization.py +14 -46
  61. glaip_sdk/utils/validation.py +4 -4
  62. {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.1.3.dist-info}/METADATA +12 -1
  63. glaip_sdk-0.1.3.dist-info/RECORD +83 -0
  64. glaip_sdk-0.0.20.dist-info/RECORD +0 -80
  65. {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.1.3.dist-info}/WHEEL +0 -0
  66. {glaip_sdk-0.0.20.dist-info → glaip_sdk-0.1.3.dist-info}/entry_points.txt +0 -0
glaip_sdk/_version.py CHANGED
@@ -47,9 +47,7 @@ def _try_get_dev_version() -> str | None:
47
47
  return None
48
48
 
49
49
  data = _toml.loads(pyproject.read_text(encoding="utf-8"))
50
- ver = data.get("project", {}).get("version") or data.get("tool", {}).get(
51
- "poetry", {}
52
- ).get("version")
50
+ ver = data.get("project", {}).get("version") or data.get("tool", {}).get("poetry", {}).get("version")
53
51
  if isinstance(ver, str) and ver:
54
52
  return ver
55
53
  except Exception:
glaip_sdk/branding.py CHANGED
@@ -104,9 +104,7 @@ GDP Labs AI Agents Package
104
104
  @staticmethod
105
105
  def _make_console() -> Console:
106
106
  # Respect NO_COLOR/AIP_NO_COLOR environment variables
107
- no_color_env = (
108
- os.getenv("NO_COLOR") is not None or os.getenv("AIP_NO_COLOR") is not None
109
- )
107
+ no_color_env = os.getenv("NO_COLOR") is not None or os.getenv("AIP_NO_COLOR") is not None
110
108
  if no_color_env:
111
109
  color_system = None
112
110
  no_color = True
@@ -187,9 +185,7 @@ GDP Labs AI Agents Package
187
185
  self.console.print(banner)
188
186
 
189
187
  @classmethod
190
- def create_from_sdk(
191
- cls, sdk_version: str | None = None, package_name: str | None = None
192
- ) -> AIPBranding:
188
+ def create_from_sdk(cls, sdk_version: str | None = None, package_name: str | None = None) -> AIPBranding:
193
189
  """Create AIPBranding instance from SDK package information.
194
190
 
195
191
  Args:
@@ -16,9 +16,7 @@ from glaip_sdk.utils.agent_config import (
16
16
  from glaip_sdk.utils.import_export import merge_import_with_cli_args
17
17
 
18
18
 
19
- def merge_agent_config_with_cli_args(
20
- import_data: dict[str, Any], cli_args: dict[str, Any]
21
- ) -> dict[str, Any]:
19
+ def merge_agent_config_with_cli_args(import_data: dict[str, Any], cli_args: dict[str, Any]) -> dict[str, Any]:
22
20
  """Merge imported agent data with CLI arguments, preferring CLI args.
23
21
 
24
22
  This is a CLI-specific wrapper that handles agent-specific merging logic.
@@ -35,9 +33,7 @@ def merge_agent_config_with_cli_args(
35
33
  - Handles agent-specific fields like tools and agents arrays
36
34
  - Preserves agent configuration structure
37
35
  """
38
- return merge_import_with_cli_args(
39
- import_data, cli_args, array_fields=["tools", "agents"]
40
- )
36
+ return merge_import_with_cli_args(import_data, cli_args, array_fields=["tools", "agents"])
41
37
 
42
38
 
43
39
  def resolve_agent_language_model_selection(
glaip_sdk/cli/auth.py CHANGED
@@ -65,9 +65,7 @@ def prepare_authentication_export(
65
65
 
66
66
  # Handle bearer-token authentication
67
67
  if auth_type == "bearer-token":
68
- return _prepare_bearer_token_auth(
69
- auth, prompt_for_secrets, placeholder, console
70
- )
68
+ return _prepare_bearer_token_auth(auth, prompt_for_secrets, placeholder, console)
71
69
 
72
70
  # Handle api-key authentication
73
71
  if auth_type == "api-key":
@@ -75,9 +73,7 @@ def prepare_authentication_export(
75
73
 
76
74
  # Handle custom-header authentication
77
75
  if auth_type == "custom-header":
78
- return _prepare_custom_header_auth(
79
- auth, prompt_for_secrets, placeholder, console
80
- )
76
+ return _prepare_custom_header_auth(auth, prompt_for_secrets, placeholder, console)
81
77
 
82
78
  # Unknown auth type - return as-is but strip helper metadata
83
79
  result = auth.copy()
@@ -85,9 +81,7 @@ def prepare_authentication_export(
85
81
  return result
86
82
 
87
83
 
88
- def _get_token_value(
89
- prompt_for_secrets: bool, placeholder: str, console: Console
90
- ) -> str:
84
+ def _get_token_value(prompt_for_secrets: bool, placeholder: str, console: Console) -> str:
91
85
  """Get bearer token value either by prompting or using a placeholder.
92
86
 
93
87
  Args:
@@ -109,10 +103,7 @@ def _get_token_value(
109
103
  )
110
104
 
111
105
  if not click.get_text_stream("stdin").isatty():
112
- console.print(
113
- f"[{WARNING_STYLE}]⚠️ Non-interactive mode: "
114
- "using placeholder for bearer token[/]"
115
- )
106
+ console.print(f"[{WARNING_STYLE}]⚠️ Non-interactive mode: using placeholder for bearer token[/]")
116
107
  return placeholder
117
108
 
118
109
 
@@ -220,16 +211,11 @@ def _get_api_key_value(
220
211
  )
221
212
 
222
213
  if not click.get_text_stream("stdin").isatty():
223
- console.print(
224
- f"[{WARNING_STYLE}]⚠️ Non-interactive mode: "
225
- f"using placeholder for API key '{key_name}'[/]"
226
- )
214
+ console.print(f"[{WARNING_STYLE}]⚠️ Non-interactive mode: using placeholder for API key '{key_name}'[/]")
227
215
  return placeholder
228
216
 
229
217
 
230
- def _build_api_key_headers(
231
- auth: dict[str, Any], key_name: str | None, key_value: str
232
- ) -> dict[str, str]:
218
+ def _build_api_key_headers(auth: dict[str, Any], key_name: str | None, key_value: str) -> dict[str, str]:
233
219
  """Build headers for API key authentication.
234
220
 
235
221
  Args:
@@ -270,9 +256,7 @@ def _prepare_api_key_auth(
270
256
 
271
257
  # Capture or use placeholder for value
272
258
  if not has_valid_value:
273
- key_value = _get_api_key_value(
274
- key_name, prompt_for_secrets, placeholder, console
275
- )
259
+ key_value = _get_api_key_value(key_name, prompt_for_secrets, placeholder, console)
276
260
 
277
261
  # Check if original had headers structure
278
262
  if "headers" in auth or "header_keys" in auth:
@@ -317,9 +301,7 @@ def _prepare_custom_header_auth(
317
301
  return {"type": "custom-header", "headers": headers}
318
302
 
319
303
 
320
- def _extract_header_names(
321
- existing_headers: Mapping[str, Any] | None, header_keys: Iterable[str] | None
322
- ) -> list[str]:
304
+ def _extract_header_names(existing_headers: Mapping[str, Any] | None, header_keys: Iterable[str] | None) -> list[str]:
323
305
  """Extract the list of header names to process.
324
306
 
325
307
  Args:
@@ -376,9 +358,7 @@ def _prompt_or_placeholder(
376
358
  )
377
359
 
378
360
  if not click.get_text_stream("stdin").isatty():
379
- console.print(
380
- f"[{WARNING_STYLE}]⚠️ Non-interactive mode: using placeholder for header '{name}'[/]"
381
- )
361
+ console.print(f"[{WARNING_STYLE}]⚠️ Non-interactive mode: using placeholder for header '{name}'[/]")
382
362
  return placeholder
383
363
 
384
364
 
@@ -450,7 +430,8 @@ def _prompt_secret_with_placeholder(
450
430
  tip = command_hint(tip_cli_command, tip_slash_command)
451
431
  if tip:
452
432
  console.print(
453
- f"[{HINT_PREFIX_STYLE}]Tip:[/] use {format_command_hint(tip) or tip} later if you want to update these credentials."
433
+ f"[{HINT_PREFIX_STYLE}]Tip:[/] use {format_command_hint(tip) or tip} later "
434
+ "if you want to update these credentials."
454
435
  )
455
436
 
456
437
  attempts = 0
@@ -83,6 +83,7 @@ from glaip_sdk.icons import ICON_AGENT
83
83
  from glaip_sdk.utils import format_datetime, is_uuid
84
84
  from glaip_sdk.utils.agent_config import normalize_agent_config_for_import
85
85
  from glaip_sdk.utils.import_export import convert_export_to_import_format
86
+ from glaip_sdk.utils.rendering.renderer.toggle import TranscriptToggleController
86
87
  from glaip_sdk.utils.validation import coerce_timeout
87
88
 
88
89
  console = Console()
@@ -246,9 +247,7 @@ def _resolve_resources_by_name(
246
247
  if not matches:
247
248
  raise click.ClickException(f"{label} not found: {ref}")
248
249
  if len(matches) > 1:
249
- raise click.ClickException(
250
- f"Multiple {resource_type}s named '{ref}'. Use ID instead."
251
- )
250
+ raise click.ClickException(f"Multiple {resource_type}s named '{ref}'. Use ID instead.")
252
251
  out.append(str(matches[0].id))
253
252
  return out
254
253
 
@@ -394,15 +393,9 @@ def _resolve_agent(
394
393
 
395
394
 
396
395
  @agents_group.command(name="list")
397
- @click.option(
398
- "--simple", is_flag=True, help="Show simple table without interactive picker"
399
- )
400
- @click.option(
401
- "--type", "agent_type", help="Filter by agent type (config, code, a2a, langflow)"
402
- )
403
- @click.option(
404
- "--framework", help="Filter by framework (langchain, langgraph, google_adk)"
405
- )
396
+ @click.option("--simple", is_flag=True, help="Show simple table without interactive picker")
397
+ @click.option("--type", "agent_type", help="Filter by agent type (config, code, a2a, langflow)")
398
+ @click.option("--framework", help="Filter by framework (langchain, langgraph, google_adk)")
406
399
  @click.option("--name", help="Filter by partial name match (case-insensitive)")
407
400
  @click.option("--version", help="Filter by exact version match")
408
401
  @click.option(
@@ -481,15 +474,12 @@ def list_agents(
481
474
  f"{ICON_AGENT} Available Agents",
482
475
  columns,
483
476
  transform_agent,
484
- skip_picker=simple
485
- or any(
486
- param is not None for param in (agent_type, framework, name, version)
487
- ),
477
+ skip_picker=simple or any(param is not None for param in (agent_type, framework, name, version)),
488
478
  use_pager=False,
489
479
  )
490
480
 
491
481
  except Exception as e:
492
- raise click.ClickException(str(e))
482
+ raise click.ClickException(str(e)) from e
493
483
 
494
484
 
495
485
  @agents_group.command()
@@ -514,9 +504,7 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
514
504
  client = get_client(ctx)
515
505
 
516
506
  # Resolve agent with ambiguity handling - use questionary interface for traditional UX
517
- agent = _resolve_agent(
518
- ctx, client, agent_ref, select, interface_preference="questionary"
519
- )
507
+ agent = _resolve_agent(ctx, client, agent_ref, select, interface_preference="questionary")
520
508
 
521
509
  # Handle export option
522
510
  if export:
@@ -535,22 +523,19 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
535
523
  except Exception as e:
536
524
  handle_rich_output(
537
525
  ctx,
538
- markup_text(
539
- f"[{WARNING_STYLE}]⚠️ Could not fetch full agent details: {e}[/]"
540
- ),
526
+ markup_text(f"[{WARNING_STYLE}]⚠️ Could not fetch full agent details: {e}[/]"),
541
527
  )
542
528
  handle_rich_output(
543
529
  ctx,
544
- markup_text(
545
- f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]"
546
- ),
530
+ markup_text(f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]"),
547
531
  )
548
532
 
549
533
  export_resource_to_file(agent, export_path, detected_format)
550
534
  handle_rich_output(
551
535
  ctx,
552
536
  markup_text(
553
- f"[{SUCCESS_STYLE}]✅ Complete agent configuration exported to: {export_path} (format: {detected_format})[/]"
537
+ f"[{SUCCESS_STYLE}]✅ Complete agent configuration exported to: {export_path} "
538
+ f"(format: {detected_format})[/]"
554
539
  ),
555
540
  )
556
541
 
@@ -561,7 +546,7 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
561
546
  handle_rich_output(ctx, display_agent_run_suggestions(agent))
562
547
 
563
548
  except Exception as e:
564
- raise click.ClickException(str(e))
549
+ raise click.ClickException(str(e)) from e
565
550
 
566
551
 
567
552
  def _validate_run_input(input_option: str | None, input_text: str | None) -> str:
@@ -569,9 +554,7 @@ def _validate_run_input(input_option: str | None, input_text: str | None) -> str
569
554
  final_input_text = input_option if input_option else input_text
570
555
 
571
556
  if not final_input_text:
572
- raise click.ClickException(
573
- "Input text is required. Use either positional argument or --input option."
574
- )
557
+ raise click.ClickException("Input text is required. Use either positional argument or --input option.")
575
558
 
576
559
  return final_input_text
577
560
 
@@ -583,8 +566,8 @@ def _parse_chat_history(chat_history: str | None) -> list[dict[str, Any]] | None
583
566
 
584
567
  try:
585
568
  return json.loads(chat_history)
586
- except json.JSONDecodeError:
587
- raise click.ClickException("Invalid JSON in chat history")
569
+ except json.JSONDecodeError as err:
570
+ raise click.ClickException("Invalid JSON in chat history") from err
588
571
 
589
572
 
590
573
  def _setup_run_renderer(ctx: Any, save: str | None, verbose: bool) -> Any:
@@ -598,6 +581,23 @@ def _setup_run_renderer(ctx: Any, save: str | None, verbose: bool) -> Any:
598
581
  )
599
582
 
600
583
 
584
+ def _maybe_attach_transcript_toggle(ctx: Any, renderer: Any) -> None:
585
+ """Attach transcript toggle controller when interactive TTY is available."""
586
+ if renderer is None:
587
+ return
588
+
589
+ console_obj = getattr(renderer, "console", None)
590
+ if console_obj is None or not getattr(console_obj, "is_terminal", False):
591
+ return
592
+
593
+ tty_enabled = bool(get_ctx_value(ctx, "tty", True))
594
+ if not tty_enabled:
595
+ return
596
+
597
+ controller = TranscriptToggleController(enabled=True)
598
+ renderer.transcript_controller = controller
599
+
600
+
601
601
  def _prepare_run_kwargs(
602
602
  agent: Any,
603
603
  final_input_text: str,
@@ -647,9 +647,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
647
647
  if ext == "json":
648
648
  save_data = {
649
649
  "output": result or "",
650
- "full_debug_output": getattr(
651
- working_console, "get_captured_output", lambda: ""
652
- )(),
650
+ "full_debug_output": getattr(working_console, "get_captured_output", lambda: "")(),
653
651
  "timestamp": "captured during agent execution",
654
652
  }
655
653
  content = json.dumps(save_data, indent=2)
@@ -662,9 +660,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
662
660
 
663
661
  with open(save, "w", encoding="utf-8") as f:
664
662
  f.write(content)
665
- print_markup(
666
- f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console
667
- )
663
+ print_markup(f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console)
668
664
 
669
665
 
670
666
  @agents_group.command()
@@ -727,12 +723,11 @@ def run(
727
723
 
728
724
  try:
729
725
  client = get_client(ctx)
730
- agent = _resolve_agent(
731
- ctx, client, agent_ref, select, interface_preference="fuzzy"
732
- )
726
+ agent = _resolve_agent(ctx, client, agent_ref, select, interface_preference="fuzzy")
733
727
 
734
728
  parsed_chat_history = _parse_chat_history(chat_history)
735
729
  renderer, working_console = _setup_run_renderer(ctx, save, verbose)
730
+ _maybe_attach_transcript_toggle(ctx, renderer)
736
731
 
737
732
  try:
738
733
  client.timeout = float(timeout)
@@ -777,7 +772,7 @@ def run(
777
772
  except AgentTimeoutError as e:
778
773
  error_msg = str(e)
779
774
  handle_json_output(ctx, error=Exception(error_msg))
780
- raise click.ClickException(error_msg)
775
+ raise click.ClickException(error_msg) from e
781
776
  except Exception as e:
782
777
  _handle_command_exception(ctx, e)
783
778
 
@@ -866,16 +861,12 @@ def _extract_and_validate_fields(
866
861
  if not name:
867
862
  raise click.ClickException("Agent name is required (--name or --import)")
868
863
  if not instruction:
869
- raise click.ClickException(
870
- "Agent instruction is required (--instruction or --import)"
871
- )
864
+ raise click.ClickException("Agent instruction is required (--instruction or --import)")
872
865
 
873
866
  return name, instruction, model, tools, agents, mcps, timeout
874
867
 
875
868
 
876
- def _validate_and_coerce_fields(
877
- name: str, instruction: str, timeout: Any
878
- ) -> tuple[str, str, Any]:
869
+ def _validate_and_coerce_fields(name: str, instruction: str, timeout: Any) -> tuple[str, str, Any]:
879
870
  """Validate and coerce field values."""
880
871
  name = validate_agent_name(name)
881
872
  instruction = validate_agent_instruction(instruction)
@@ -886,19 +877,11 @@ def _validate_and_coerce_fields(
886
877
  return name, instruction, timeout
887
878
 
888
879
 
889
- def _resolve_resources(
890
- client: Any, tools: tuple, agents: tuple, mcps: tuple
891
- ) -> tuple[list, list, list]:
880
+ def _resolve_resources(client: Any, tools: tuple, agents: tuple, mcps: tuple) -> tuple[list, list, list]:
892
881
  """Resolve tool, agent, and MCP references."""
893
- resolved_tools = _resolve_resources_by_name(
894
- client, tools, "tool", client.find_tools, "Tool"
895
- )
896
- resolved_agents = _resolve_resources_by_name(
897
- client, agents, "agent", client.find_agents, "Agent"
898
- )
899
- resolved_mcps = _resolve_resources_by_name(
900
- client, mcps, "mcp", client.find_mcps, "MCP"
901
- )
882
+ resolved_tools = _resolve_resources_by_name(client, tools, "tool", client.find_tools, "Tool")
883
+ resolved_agents = _resolve_resources_by_name(client, agents, "agent", client.find_agents, "Agent")
884
+ resolved_mcps = _resolve_resources_by_name(client, mcps, "mcp", client.find_mcps, "MCP")
902
885
 
903
886
  return resolved_tools, resolved_agents, resolved_mcps
904
887
 
@@ -925,16 +908,12 @@ def _build_create_kwargs(
925
908
  }
926
909
 
927
910
  # Handle language model selection
928
- lm_selection_dict, should_strip_lm_identity = resolve_language_model_selection(
929
- merged_data, model
930
- )
911
+ lm_selection_dict, should_strip_lm_identity = resolve_language_model_selection(merged_data, model)
931
912
  create_kwargs.update(lm_selection_dict)
932
913
 
933
914
  # Handle import file specific logic
934
915
  if import_file:
935
- _add_import_file_attributes(
936
- create_kwargs, merged_data, should_strip_lm_identity
937
- )
916
+ _add_import_file_attributes(create_kwargs, merged_data, should_strip_lm_identity)
938
917
 
939
918
  return create_kwargs
940
919
 
@@ -980,12 +959,7 @@ def _get_language_model_display_name(agent: Any, model: str | None) -> str:
980
959
  lm_display = getattr(agent, "model", None)
981
960
  if not lm_display:
982
961
  cfg = getattr(agent, "agent_config", {}) or {}
983
- lm_display = (
984
- cfg.get("lm_name")
985
- or cfg.get("model")
986
- or model
987
- or f"{DEFAULT_MODEL} (backend default)"
988
- )
962
+ lm_display = cfg.get("lm_name") or cfg.get("model") or model or f"{DEFAULT_MODEL} (backend default)"
989
963
  return lm_display
990
964
 
991
965
 
@@ -1020,7 +994,7 @@ def _handle_command_exception(ctx: Any, e: Exception) -> None:
1020
994
  handle_json_output(ctx, error=e)
1021
995
  if get_ctx_value(ctx, "view") != "json":
1022
996
  print_api_error(e)
1023
- raise click.ClickException(str(e))
997
+ raise click.exceptions.Exit(1) from e
1024
998
 
1025
999
 
1026
1000
  def _handle_creation_exception(ctx: Any, e: Exception) -> None:
@@ -1074,13 +1048,9 @@ def create(
1074
1048
 
1075
1049
  # Handle import file or CLI args
1076
1050
  if import_file:
1077
- merged_data = _handle_import_file_logic(
1078
- import_file, model, name, instruction, tools, agents, mcps, timeout
1079
- )
1051
+ merged_data = _handle_import_file_logic(import_file, model, name, instruction, tools, agents, mcps, timeout)
1080
1052
  else:
1081
- merged_data = _build_cli_args_data(
1082
- name, instruction, model, tools, agents, mcps, timeout
1083
- )
1053
+ merged_data = _build_cli_args_data(name, instruction, model, tools, agents, mcps, timeout)
1084
1054
 
1085
1055
  # Extract and validate fields
1086
1056
  (
@@ -1092,14 +1062,10 @@ def create(
1092
1062
  mcps,
1093
1063
  timeout,
1094
1064
  ) = _extract_and_validate_fields(merged_data)
1095
- name, instruction, timeout = _validate_and_coerce_fields(
1096
- name, instruction, timeout
1097
- )
1065
+ name, instruction, timeout = _validate_and_coerce_fields(name, instruction, timeout)
1098
1066
 
1099
1067
  # Resolve resources
1100
- resolved_tools, resolved_agents, resolved_mcps = _resolve_resources(
1101
- client, tools, agents, mcps
1102
- )
1068
+ resolved_tools, resolved_agents, resolved_mcps = _resolve_resources(client, tools, agents, mcps)
1103
1069
 
1104
1070
  # Build create kwargs
1105
1071
  create_kwargs = _build_create_kwargs(
@@ -1129,7 +1095,7 @@ def _get_agent_for_update(client: Any, agent_id: str) -> Any:
1129
1095
  try:
1130
1096
  return client.agents.get_agent_by_id(agent_id)
1131
1097
  except Exception as e:
1132
- raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
1098
+ raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}") from e
1133
1099
 
1134
1100
 
1135
1101
  def _handle_update_import_file(
@@ -1211,16 +1177,12 @@ def _handle_update_import_config(
1211
1177
  if not import_file:
1212
1178
  return
1213
1179
 
1214
- lm_selection, should_strip_lm_identity = resolve_language_model_selection(
1215
- merged_data, None
1216
- )
1180
+ lm_selection, should_strip_lm_identity = resolve_language_model_selection(merged_data, None)
1217
1181
  update_data.update(lm_selection)
1218
1182
 
1219
1183
  raw_cfg = merged_data.get("agent_config") if isinstance(merged_data, dict) else None
1220
1184
  if isinstance(raw_cfg, dict):
1221
- update_data["agent_config"] = sanitize_agent_config(
1222
- raw_cfg, strip_lm_identity=should_strip_lm_identity
1223
- )
1185
+ update_data["agent_config"] = sanitize_agent_config(raw_cfg, strip_lm_identity=should_strip_lm_identity)
1224
1186
 
1225
1187
  excluded_fields = {
1226
1188
  "name",
@@ -1289,13 +1251,9 @@ def update(
1289
1251
  agents,
1290
1252
  mcps,
1291
1253
  timeout,
1292
- ) = _handle_update_import_file(
1293
- import_file, name, instruction, tools, agents, mcps, timeout
1294
- )
1254
+ ) = _handle_update_import_file(import_file, name, instruction, tools, agents, mcps, timeout)
1295
1255
 
1296
- update_data = _build_update_data(
1297
- name, instruction, tools, agents, mcps, timeout
1298
- )
1256
+ update_data = _build_update_data(name, instruction, tools, agents, mcps, timeout)
1299
1257
 
1300
1258
  if merged_data:
1301
1259
  _handle_update_import_config(import_file, merged_data, update_data)
@@ -1333,7 +1291,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
1333
1291
  try:
1334
1292
  agent = client.agents.get_agent_by_id(agent_id)
1335
1293
  except Exception as e:
1336
- raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}")
1294
+ raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}") from e
1337
1295
 
1338
1296
  # Confirm deletion when not forced
1339
1297
  if not yes and not display_confirmation_prompt("Agent", agent.name):
@@ -1365,9 +1323,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
1365
1323
  "--base-url",
1366
1324
  help="Custom LangFlow server base URL (overrides LANGFLOW_BASE_URL env var)",
1367
1325
  )
1368
- @click.option(
1369
- "--api-key", help="Custom LangFlow API key (overrides LANGFLOW_API_KEY env var)"
1370
- )
1326
+ @click.option("--api-key", help="Custom LangFlow API key (overrides LANGFLOW_API_KEY env var)")
1371
1327
  @output_flags()
1372
1328
  @click.pass_context
1373
1329
  def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
@@ -1396,15 +1352,16 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
1396
1352
  # Show success message for non-JSON output
1397
1353
  if get_ctx_value(ctx, "view") != "json":
1398
1354
  # Extract some useful info from the result
1399
- success_count = result.get("data", {}).get("created_count", 0) + result.get(
1400
- "data", {}
1401
- ).get("updated_count", 0)
1355
+ success_count = result.get("data", {}).get("created_count", 0) + result.get("data", {}).get(
1356
+ "updated_count", 0
1357
+ )
1402
1358
  total_count = result.get("data", {}).get("total_processed", 0)
1403
1359
 
1404
1360
  handle_rich_output(
1405
1361
  ctx,
1406
1362
  markup_text(
1407
- f"[{SUCCESS_STYLE}]✅ Successfully synced {success_count} LangFlow agents ({total_count} total processed)[/]"
1363
+ f"[{SUCCESS_STYLE}]✅ Successfully synced {success_count} LangFlow agents "
1364
+ f"({total_count} total processed)[/]"
1408
1365
  ),
1409
1366
  )
1410
1367
 
@@ -57,9 +57,7 @@ def set_config(key: str, value: str) -> None:
57
57
  valid_keys = ["api_url", "api_key"]
58
58
 
59
59
  if key not in valid_keys:
60
- console.print(
61
- f"[{ERROR_STYLE}]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/]"
62
- )
60
+ console.print(f"[{ERROR_STYLE}]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/]")
63
61
  raise click.ClickException(f"Invalid configuration key: {key}")
64
62
 
65
63
  config = load_config()
@@ -67,9 +65,7 @@ def set_config(key: str, value: str) -> None:
67
65
  save_config(config)
68
66
 
69
67
  if key == "api_key":
70
- console.print(
71
- Text(f"✅ Set {key} = {_mask_api_key(value)}", style=SUCCESS_STYLE)
72
- )
68
+ console.print(Text(f"✅ Set {key} = {_mask_api_key(value)}", style=SUCCESS_STYLE))
73
69
  else:
74
70
  console.print(Text(f"✅ Set {key} = {value}", style=SUCCESS_STYLE))
75
71
 
@@ -81,9 +77,7 @@ def get_config(key: str) -> None:
81
77
  config = load_config()
82
78
 
83
79
  if key not in config:
84
- console.print(
85
- markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]")
86
- )
80
+ console.print(markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]"))
87
81
  raise click.ClickException(f"Configuration key not found: {key}")
88
82
 
89
83
  value = config[key]
@@ -101,9 +95,7 @@ def unset_config(key: str) -> None:
101
95
  config = load_config()
102
96
 
103
97
  if key not in config:
104
- console.print(
105
- markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]")
106
- )
98
+ console.print(markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]"))
107
99
  return
108
100
 
109
101
  del config[key]
@@ -128,9 +120,7 @@ def reset_config(force: bool) -> None:
128
120
 
129
121
  if not file_exists and not config_data:
130
122
  console.print(f"[{WARNING_STYLE}]No configuration found to reset.[/]")
131
- console.print(
132
- Text("✅ Configuration reset (nothing to remove).", style=SUCCESS_STYLE)
133
- )
123
+ console.print(Text("✅ Configuration reset (nothing to remove).", style=SUCCESS_STYLE))
134
124
  return
135
125
 
136
126
  if file_exists:
@@ -188,9 +178,7 @@ def _mask_api_key(value: str | None) -> str:
188
178
  def _print_missing_config_hint() -> None:
189
179
  hint = command_hint("config configure", slash_command="login")
190
180
  if hint:
191
- console.print(
192
- f"[{WARNING_STYLE}]No configuration found.[/] Run {format_command_hint(hint) or hint} to set up."
193
- )
181
+ console.print(f"[{WARNING_STYLE}]No configuration found.[/] Run {format_command_hint(hint) or hint} to set up.")
194
182
  else:
195
183
  console.print(f"[{WARNING_STYLE}]No configuration found.[/]")
196
184
 
@@ -208,9 +196,7 @@ def _render_config_table(config: dict[str, str]) -> None:
208
196
 
209
197
 
210
198
  def _render_configuration_header() -> None:
211
- branding = AIPBranding.create_from_sdk(
212
- sdk_version=_SDK_VERSION, package_name="glaip-sdk"
213
- )
199
+ branding = AIPBranding.create_from_sdk(sdk_version=_SDK_VERSION, package_name="glaip-sdk")
214
200
  heading = "[bold]>_ GDP Labs AI Agents Package (AIP CLI)[/bold]"
215
201
  console.print(heading)
216
202
  console.print()
@@ -249,9 +235,7 @@ def _prompt_api_key(config: dict[str, str]) -> None:
249
235
 
250
236
  def _save_configuration(config: dict[str, str]) -> None:
251
237
  save_config(config)
252
- console.print(
253
- Text(f"\n✅ Configuration saved to: {CONFIG_FILE}", style=SUCCESS_STYLE)
254
- )
238
+ console.print(Text(f"\n✅ Configuration saved to: {CONFIG_FILE}", style=SUCCESS_STYLE))
255
239
 
256
240
 
257
241
  def _test_and_report_connection(config: dict[str, str]) -> None:
@@ -274,17 +258,13 @@ def _test_and_report_connection(config: dict[str, str]) -> None:
274
258
  style=WARNING_STYLE,
275
259
  )
276
260
  )
277
- console.print(
278
- " You may need to check your API permissions or network access"
279
- )
261
+ console.print(" You may need to check your API permissions or network access")
280
262
  except Exception as exc:
281
263
  console.print(Text(f"❌ Connection failed: {exc}"))
282
264
  console.print(" Please check your API URL and key")
283
265
  hint_status = command_hint("status", slash_command="status")
284
266
  if hint_status:
285
- console.print(
286
- f" You can run {format_command_hint(hint_status) or hint_status} later to test again"
287
- )
267
+ console.print(f" You can run {format_command_hint(hint_status) or hint_status} later to test again")
288
268
  finally:
289
269
  if client is not None:
290
270
  client.close()
@@ -294,11 +274,7 @@ def _print_post_configuration_hints() -> None:
294
274
  console.print("\n💡 You can now use AIP CLI commands!")
295
275
  hint_status = command_hint("status", slash_command="status")
296
276
  if hint_status:
297
- console.print(
298
- f" • Run {format_command_hint(hint_status) or hint_status} to check connection"
299
- )
277
+ console.print(f" • Run {format_command_hint(hint_status) or hint_status} to check connection")
300
278
  hint_agents = command_hint("agents list", slash_command="agents")
301
279
  if hint_agents:
302
- console.print(
303
- f" • Run {format_command_hint(hint_agents) or hint_agents} to see your agents"
304
- )
280
+ console.print(f" • Run {format_command_hint(hint_agents) or hint_agents} to see your agents")