glaip-sdk 0.0.5__py3-none-any.whl → 0.0.6a0__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 (42) hide show
  1. glaip_sdk/__init__.py +1 -1
  2. glaip_sdk/branding.py +3 -2
  3. glaip_sdk/cli/commands/__init__.py +1 -1
  4. glaip_sdk/cli/commands/agents.py +444 -268
  5. glaip_sdk/cli/commands/configure.py +12 -11
  6. glaip_sdk/cli/commands/mcps.py +28 -16
  7. glaip_sdk/cli/commands/models.py +5 -3
  8. glaip_sdk/cli/commands/tools.py +109 -102
  9. glaip_sdk/cli/display.py +38 -16
  10. glaip_sdk/cli/io.py +1 -1
  11. glaip_sdk/cli/main.py +26 -5
  12. glaip_sdk/cli/resolution.py +5 -4
  13. glaip_sdk/cli/utils.py +376 -157
  14. glaip_sdk/cli/validators.py +7 -2
  15. glaip_sdk/client/agents.py +184 -89
  16. glaip_sdk/client/base.py +24 -13
  17. glaip_sdk/client/validators.py +154 -94
  18. glaip_sdk/config/constants.py +0 -2
  19. glaip_sdk/models.py +4 -4
  20. glaip_sdk/utils/__init__.py +7 -7
  21. glaip_sdk/utils/client_utils.py +144 -78
  22. glaip_sdk/utils/display.py +4 -2
  23. glaip_sdk/utils/general.py +8 -6
  24. glaip_sdk/utils/import_export.py +55 -24
  25. glaip_sdk/utils/rendering/formatting.py +12 -6
  26. glaip_sdk/utils/rendering/models.py +1 -1
  27. glaip_sdk/utils/rendering/renderer/base.py +412 -248
  28. glaip_sdk/utils/rendering/renderer/console.py +6 -5
  29. glaip_sdk/utils/rendering/renderer/debug.py +94 -52
  30. glaip_sdk/utils/rendering/renderer/stream.py +93 -48
  31. glaip_sdk/utils/rendering/steps.py +103 -39
  32. glaip_sdk/utils/rich_utils.py +1 -1
  33. glaip_sdk/utils/run_renderer.py +1 -1
  34. glaip_sdk/utils/serialization.py +3 -1
  35. glaip_sdk/utils/validation.py +2 -2
  36. glaip_sdk-0.0.6a0.dist-info/METADATA +183 -0
  37. glaip_sdk-0.0.6a0.dist-info/RECORD +55 -0
  38. {glaip_sdk-0.0.5.dist-info → glaip_sdk-0.0.6a0.dist-info}/WHEEL +1 -1
  39. glaip_sdk-0.0.6a0.dist-info/entry_points.txt +3 -0
  40. glaip_sdk-0.0.5.dist-info/METADATA +0 -645
  41. glaip_sdk-0.0.5.dist-info/RECORD +0 -55
  42. glaip_sdk-0.0.5.dist-info/entry_points.txt +0 -2
@@ -5,7 +5,9 @@ Authors:
5
5
  """
6
6
 
7
7
  import re
8
+ from collections.abc import Iterable, Iterator
8
9
  from datetime import datetime
10
+ from typing import Any
9
11
  from uuid import UUID
10
12
 
11
13
  import click
@@ -58,7 +60,7 @@ def format_file_size(size_bytes: int) -> str:
58
60
  return f"{size_bytes:.1f} TB"
59
61
 
60
62
 
61
- def format_datetime(dt):
63
+ def format_datetime(dt: datetime | str | None) -> str:
62
64
  """Format datetime object to readable string.
63
65
 
64
66
  Args:
@@ -74,7 +76,9 @@ def format_datetime(dt):
74
76
  return str(dt)
75
77
 
76
78
 
77
- def progress_bar(iterable, description: str = "Processing"):
79
+ def progress_bar(
80
+ iterable: Iterable[Any], description: str = "Processing"
81
+ ) -> Iterator[Any]:
78
82
  """Simple progress bar using click.
79
83
 
80
84
  Args:
@@ -86,9 +90,7 @@ def progress_bar(iterable, description: str = "Processing"):
86
90
  """
87
91
  try:
88
92
  with click.progressbar(iterable, label=description) as bar:
89
- for item in bar:
90
- yield item
93
+ yield from bar
91
94
  except ImportError:
92
95
  # Fallback if click not available
93
- for item in iterable:
94
- yield item
96
+ yield from iterable
@@ -66,6 +66,58 @@ def convert_export_to_import_format(data: dict[str, Any]) -> dict[str, Any]:
66
66
  return import_data
67
67
 
68
68
 
69
+ def _get_default_array_fields() -> list[str]:
70
+ """Get default array fields that should be merged."""
71
+ return ["tools", "agents"]
72
+
73
+
74
+ def _should_use_cli_value(cli_value: Any) -> bool:
75
+ """Check if CLI value should be used."""
76
+ return cli_value is not None and (
77
+ not isinstance(cli_value, list | tuple) or len(cli_value) > 0
78
+ )
79
+
80
+
81
+ def _handle_array_field_merge(
82
+ key: str, cli_value: Any, import_data: dict[str, Any]
83
+ ) -> Any:
84
+ """Handle merging of array fields."""
85
+ import_value = import_data[key]
86
+ if isinstance(import_value, list):
87
+ return list(cli_value) + import_value
88
+ else:
89
+ return cli_value
90
+
91
+
92
+ def _merge_cli_values_with_import(
93
+ merged: dict[str, Any],
94
+ cli_args: dict[str, Any],
95
+ import_data: dict[str, Any],
96
+ array_fields: list[str],
97
+ ) -> None:
98
+ """Merge CLI values into merged dict."""
99
+ for key, cli_value in cli_args.items():
100
+ if _should_use_cli_value(cli_value):
101
+ # CLI value takes precedence (for non-empty values)
102
+ if key in array_fields and key in import_data:
103
+ # For array fields, combine CLI and imported values
104
+ merged[key] = _handle_array_field_merge(key, cli_value, import_data)
105
+ else:
106
+ merged[key] = cli_value
107
+ elif key in import_data:
108
+ # Use imported value if no CLI value
109
+ merged[key] = import_data[key]
110
+
111
+
112
+ def _add_import_only_fields(
113
+ merged: dict[str, Any], import_data: dict[str, Any]
114
+ ) -> None:
115
+ """Add fields that exist only in import data."""
116
+ for key, import_value in import_data.items():
117
+ if key not in merged:
118
+ merged[key] = import_value
119
+
120
+
69
121
  def merge_import_with_cli_args(
70
122
  import_data: dict[str, Any],
71
123
  cli_args: dict[str, Any],
@@ -87,32 +139,11 @@ def merge_import_with_cli_args(
87
139
  - Empty arrays/lists are treated as None (no override)
88
140
  """
89
141
  if array_fields is None:
90
- array_fields = ["tools", "agents"]
142
+ array_fields = _get_default_array_fields()
91
143
 
92
144
  merged = {}
93
-
94
- for key, cli_value in cli_args.items():
95
- if cli_value is not None and (
96
- not isinstance(cli_value, list | tuple) or len(cli_value) > 0
97
- ):
98
- # CLI value takes precedence (for non-empty values)
99
- if key in array_fields and key in import_data:
100
- # For array fields, combine CLI and imported values
101
- import_value = import_data[key]
102
- if isinstance(import_value, list):
103
- merged[key] = list(cli_value) + import_value
104
- else:
105
- merged[key] = cli_value
106
- else:
107
- merged[key] = cli_value
108
- elif key in import_data:
109
- # Use imported value if no CLI value
110
- merged[key] = import_data[key]
111
-
112
- # Add any import-only fields
113
- for key, import_value in import_data.items():
114
- if key not in merged:
115
- merged[key] = import_value
145
+ _merge_cli_values_with_import(merged, cli_args, import_data, array_fields)
146
+ _add_import_only_fields(merged, import_data)
116
147
 
117
148
  return merged
118
149
 
@@ -8,6 +8,8 @@ from __future__ import annotations
8
8
 
9
9
  import re
10
10
  import time
11
+ from collections.abc import Callable
12
+ from typing import Any
11
13
 
12
14
  # Constants for argument formatting
13
15
  DEFAULT_ARGS_MAX_LEN = 100
@@ -65,9 +67,7 @@ def redact_sensitive(text: str | dict | list) -> str | dict | list:
65
67
  for sensitive in ["password", "secret", "token", "key", "api_key"]
66
68
  ):
67
69
  result[key] = "••••••"
68
- elif isinstance(value, dict | list):
69
- result[key] = redact_sensitive(value)
70
- elif isinstance(value, str):
70
+ elif isinstance(value, dict | list) or isinstance(value, str):
71
71
  result[key] = redact_sensitive(value)
72
72
  else:
73
73
  result[key] = value
@@ -156,7 +156,7 @@ def get_step_icon(step_kind: str) -> str:
156
156
  return ""
157
157
 
158
158
 
159
- def is_step_finished(step) -> bool:
159
+ def is_step_finished(step: Any) -> bool:
160
160
  """Check if a step is finished.
161
161
 
162
162
  Args:
@@ -169,7 +169,9 @@ def is_step_finished(step) -> bool:
169
169
 
170
170
 
171
171
  def format_main_title(
172
- header_text: str, has_running_steps: bool, get_spinner_char: callable
172
+ header_text: str,
173
+ has_running_steps: bool,
174
+ get_spinner_char: Callable[[], str],
173
175
  ) -> str:
174
176
  """Generate the main panel title with dynamic status indicators.
175
177
 
@@ -191,7 +193,11 @@ def format_main_title(
191
193
 
192
194
 
193
195
  def print_header_once(
194
- console, text: str, last_header: str, rules_enabled: bool, style: str | None = None
196
+ console: Any,
197
+ text: str,
198
+ last_header: str,
199
+ rules_enabled: bool,
200
+ style: str | None = None,
195
201
  ) -> str:
196
202
  """Print header text only when it changes to avoid duplicate output.
197
203
 
@@ -25,7 +25,7 @@ class Step:
25
25
  started_at: float = field(default_factory=monotonic)
26
26
  duration_ms: int | None = None
27
27
 
28
- def finish(self, duration_raw: float | None):
28
+ def finish(self, duration_raw: float | None) -> None:
29
29
  if isinstance(duration_raw, int | float) and duration_raw > 0:
30
30
  # Use provided duration if it's a positive number (even if very small)
31
31
  self.duration_ms = round(float(duration_raw) * 1000)