glaip-sdk 0.0.4__py3-none-any.whl → 0.0.5b1__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 (48) hide show
  1. glaip_sdk/__init__.py +5 -5
  2. glaip_sdk/branding.py +18 -17
  3. glaip_sdk/cli/__init__.py +1 -1
  4. glaip_sdk/cli/agent_config.py +82 -0
  5. glaip_sdk/cli/commands/__init__.py +3 -3
  6. glaip_sdk/cli/commands/agents.py +570 -673
  7. glaip_sdk/cli/commands/configure.py +2 -2
  8. glaip_sdk/cli/commands/mcps.py +148 -143
  9. glaip_sdk/cli/commands/models.py +1 -1
  10. glaip_sdk/cli/commands/tools.py +250 -179
  11. glaip_sdk/cli/display.py +244 -0
  12. glaip_sdk/cli/io.py +106 -0
  13. glaip_sdk/cli/main.py +14 -18
  14. glaip_sdk/cli/resolution.py +59 -0
  15. glaip_sdk/cli/utils.py +305 -264
  16. glaip_sdk/cli/validators.py +235 -0
  17. glaip_sdk/client/__init__.py +3 -224
  18. glaip_sdk/client/agents.py +631 -191
  19. glaip_sdk/client/base.py +66 -4
  20. glaip_sdk/client/main.py +226 -0
  21. glaip_sdk/client/mcps.py +143 -18
  22. glaip_sdk/client/tools.py +146 -11
  23. glaip_sdk/config/constants.py +10 -1
  24. glaip_sdk/models.py +42 -2
  25. glaip_sdk/rich_components.py +29 -0
  26. glaip_sdk/utils/__init__.py +18 -171
  27. glaip_sdk/utils/agent_config.py +181 -0
  28. glaip_sdk/utils/client_utils.py +159 -79
  29. glaip_sdk/utils/display.py +100 -0
  30. glaip_sdk/utils/general.py +94 -0
  31. glaip_sdk/utils/import_export.py +140 -0
  32. glaip_sdk/utils/rendering/formatting.py +6 -1
  33. glaip_sdk/utils/rendering/renderer/__init__.py +67 -8
  34. glaip_sdk/utils/rendering/renderer/base.py +340 -247
  35. glaip_sdk/utils/rendering/renderer/debug.py +3 -2
  36. glaip_sdk/utils/rendering/renderer/panels.py +11 -10
  37. glaip_sdk/utils/rendering/steps.py +1 -1
  38. glaip_sdk/utils/resource_refs.py +192 -0
  39. glaip_sdk/utils/rich_utils.py +29 -0
  40. glaip_sdk/utils/serialization.py +285 -0
  41. glaip_sdk/utils/validation.py +273 -0
  42. {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5b1.dist-info}/METADATA +22 -21
  43. glaip_sdk-0.0.5b1.dist-info/RECORD +55 -0
  44. {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5b1.dist-info}/WHEEL +1 -1
  45. glaip_sdk-0.0.5b1.dist-info/entry_points.txt +3 -0
  46. glaip_sdk/cli/commands/init.py +0 -93
  47. glaip_sdk-0.0.4.dist-info/RECORD +0 -41
  48. glaip_sdk-0.0.4.dist-info/entry_points.txt +0 -2
@@ -0,0 +1,140 @@
1
+ """Import/export utilities for schema transforms and data merging.
2
+
3
+ This module provides functions for converting between export and import formats,
4
+ merging imported data with CLI arguments, and handling relationship flattening.
5
+
6
+ Authors:
7
+ Raymond Christopher (raymond.christopher@gdplabs.id)
8
+ """
9
+
10
+ from typing import Any
11
+
12
+
13
+ def extract_ids_from_export(items: list[Any]) -> list[str]:
14
+ """Extract IDs from export format (list of dicts with id/name fields).
15
+
16
+ Args:
17
+ items: List of items (dicts with id/name or strings)
18
+
19
+ Returns:
20
+ List of extracted IDs (only items with actual IDs)
21
+
22
+ Examples:
23
+ extract_ids_from_export([{"id": "123", "name": "tool"}]) -> ["123"]
24
+ extract_ids_from_export(["123", "456"]) -> ["123", "456"]
25
+ extract_ids_from_export([{"name": "tool"}, "123"]) -> ["123"] # Skip items without ID
26
+ """
27
+ if not items:
28
+ return []
29
+
30
+ ids = []
31
+ for item in items:
32
+ if isinstance(item, str):
33
+ ids.append(item)
34
+ elif hasattr(item, "id"):
35
+ ids.append(str(item.id))
36
+ elif isinstance(item, dict) and "id" in item:
37
+ ids.append(str(item["id"]))
38
+ # Skip items without ID (don't convert to string)
39
+
40
+ return ids
41
+
42
+
43
+ def convert_export_to_import_format(data: dict[str, Any]) -> dict[str, Any]:
44
+ """Convert export format to import-compatible format (extract IDs from objects).
45
+
46
+ Args:
47
+ data: Export format data with full objects
48
+
49
+ Returns:
50
+ Import format data with extracted IDs
51
+
52
+ Notes:
53
+ - Converts tools/agents from dict objects to ID lists
54
+ - Preserves all other data unchanged
55
+ """
56
+ import_data = data.copy()
57
+
58
+ # Convert tools from dicts to IDs
59
+ if "tools" in import_data and isinstance(import_data["tools"], list):
60
+ import_data["tools"] = extract_ids_from_export(import_data["tools"])
61
+
62
+ # Convert agents from dicts to IDs
63
+ if "agents" in import_data and isinstance(import_data["agents"], list):
64
+ import_data["agents"] = extract_ids_from_export(import_data["agents"])
65
+
66
+ return import_data
67
+
68
+
69
+ def merge_import_with_cli_args(
70
+ import_data: dict[str, Any],
71
+ cli_args: dict[str, Any],
72
+ array_fields: list[str] = None,
73
+ ) -> dict[str, Any]:
74
+ """Merge imported data with CLI arguments, preferring CLI args.
75
+
76
+ Args:
77
+ import_data: Data loaded from import file
78
+ cli_args: Arguments passed via CLI
79
+ array_fields: Fields that should be combined (merged) rather than replaced
80
+
81
+ Returns:
82
+ Merged data dictionary
83
+
84
+ Notes:
85
+ - CLI arguments take precedence over imported data
86
+ - Array fields (tools, agents) are combined rather than replaced
87
+ - Empty arrays/lists are treated as None (no override)
88
+ """
89
+ if array_fields is None:
90
+ array_fields = ["tools", "agents"]
91
+
92
+ 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
116
+
117
+ return merged
118
+
119
+
120
+ def flatten_relationships_for_import(
121
+ data: dict[str, Any], fields: tuple[str, ...] = ("tools", "agents")
122
+ ) -> dict[str, Any]:
123
+ """Flatten relationship fields for import format.
124
+
125
+ This is an alias for convert_export_to_import_format with configurable fields.
126
+
127
+ Args:
128
+ data: Export format data with full objects
129
+ fields: Tuple of field names to flatten to IDs
130
+
131
+ Returns:
132
+ Import format data with specified fields flattened to IDs
133
+ """
134
+ import_data = data.copy()
135
+
136
+ for field in fields:
137
+ if field in import_data and isinstance(import_data[field], list):
138
+ import_data[field] = extract_ids_from_export(import_data[field])
139
+
140
+ return import_data
@@ -108,7 +108,7 @@ def pretty_args(args: dict | None, max_len: int = DEFAULT_ARGS_MAX_LEN) -> str:
108
108
  try:
109
109
  import json
110
110
 
111
- args_str = json.dumps(masked_args, ensure_ascii=False)
111
+ args_str = json.dumps(masked_args, ensure_ascii=False, separators=(",", ":"))
112
112
  return _truncate_string(args_str, max_len)
113
113
  except (TypeError, ValueError, Exception):
114
114
  # Fallback to string representation if JSON serialization fails
@@ -124,6 +124,11 @@ def pretty_out(output: any, max_len: int = DEFAULT_ARGS_MAX_LEN) -> str:
124
124
  if isinstance(output, str):
125
125
  # Mask secrets in string output
126
126
  masked_output = mask_secrets_in_string(output)
127
+
128
+ # Remove LaTeX commands (common math expressions)
129
+ masked_output = re.sub(r"\\[a-zA-Z]+\{[^}]*\}", "", masked_output)
130
+ masked_output = re.sub(r"\\[a-zA-Z]+", "", masked_output)
131
+
127
132
  # Strip leading/trailing whitespace but preserve internal spacing
128
133
  masked_output = masked_output.strip()
129
134
  # Replace newlines with spaces to preserve formatting
@@ -5,21 +5,78 @@ with clean separation of concerns between configuration, console handling,
5
5
  debug output, panel rendering, progress tracking, and event routing.
6
6
  """
7
7
 
8
- from .base import RichStreamRenderer
9
- from .config import RendererConfig
10
- from .console import CapturingConsole
11
- from .debug import render_debug_event
12
- from .panels import (
8
+ import io
9
+
10
+ from rich.console import Console
11
+
12
+ from glaip_sdk.rich_components import AIPPanel
13
+ from glaip_sdk.utils.rendering.renderer.base import RichStreamRenderer
14
+ from glaip_sdk.utils.rendering.renderer.config import RendererConfig
15
+ from glaip_sdk.utils.rendering.renderer.console import CapturingConsole
16
+ from glaip_sdk.utils.rendering.renderer.debug import render_debug_event
17
+ from glaip_sdk.utils.rendering.renderer.panels import (
13
18
  create_context_panel,
14
19
  create_final_panel,
15
20
  create_main_panel,
16
21
  create_tool_panel,
17
22
  )
18
- from .progress import (
23
+ from glaip_sdk.utils.rendering.renderer.progress import (
19
24
  format_tool_title,
20
25
  is_delegation_tool,
21
26
  )
22
- from .stream import StreamProcessor
27
+ from glaip_sdk.utils.rendering.renderer.stream import StreamProcessor
28
+
29
+
30
+ def make_silent_renderer() -> RichStreamRenderer:
31
+ """Create a renderer that suppresses all terminal output.
32
+
33
+ Uses an in-memory console and disables live updates/panels.
34
+ """
35
+ cfg = RendererConfig(
36
+ live=False,
37
+ persist_live=False,
38
+ show_delegate_tool_panels=False,
39
+ render_thinking=False,
40
+ )
41
+ return RichStreamRenderer(
42
+ console=Console(file=io.StringIO(), force_terminal=False), cfg=cfg
43
+ )
44
+
45
+
46
+ def make_minimal_renderer() -> RichStreamRenderer:
47
+ """Create a minimal renderer.
48
+
49
+ Prints a compact header and the user request panel, but no live updates or tool panels.
50
+ """
51
+ cfg = RendererConfig(
52
+ live=False,
53
+ persist_live=False,
54
+ show_delegate_tool_panels=False,
55
+ render_thinking=False,
56
+ )
57
+ return RichStreamRenderer(console=Console(), cfg=cfg)
58
+
59
+
60
+ def print_panel(
61
+ content: str,
62
+ *,
63
+ title: str | None = None,
64
+ border_style: str = "blue",
65
+ padding: tuple[int, int] = (1, 2),
66
+ console: Console | None = None,
67
+ ) -> None:
68
+ """Print boxed content using Rich without exposing Console/Panel at call site.
69
+
70
+ Args:
71
+ content: The text to display inside the panel.
72
+ title: Optional title for the panel.
73
+ border_style: Rich style string for the border color.
74
+ padding: (vertical, horizontal) padding inside the panel.
75
+ console: Optional Rich Console to print to; created if not provided.
76
+ """
77
+ c = console or Console()
78
+ c.print(AIPPanel(content, title=title, border_style=border_style, padding=padding))
79
+
23
80
 
24
81
  __all__ = [
25
82
  # Main classes
@@ -27,7 +84,9 @@ __all__ = [
27
84
  "RendererConfig",
28
85
  "CapturingConsole",
29
86
  "StreamProcessor",
30
- # Key functions
87
+ "make_silent_renderer",
88
+ "make_minimal_renderer",
89
+ "print_panel",
31
90
  "render_debug_event",
32
91
  "create_main_panel",
33
92
  "create_tool_panel",