glaip-sdk 0.0.18__py3-none-any.whl → 0.0.20__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 (50) hide show
  1. glaip_sdk/_version.py +2 -2
  2. glaip_sdk/branding.py +27 -2
  3. glaip_sdk/cli/auth.py +93 -28
  4. glaip_sdk/cli/commands/__init__.py +2 -2
  5. glaip_sdk/cli/commands/agents.py +108 -21
  6. glaip_sdk/cli/commands/configure.py +141 -90
  7. glaip_sdk/cli/commands/mcps.py +371 -48
  8. glaip_sdk/cli/commands/models.py +4 -3
  9. glaip_sdk/cli/commands/tools.py +27 -14
  10. glaip_sdk/cli/commands/update.py +66 -0
  11. glaip_sdk/cli/config.py +13 -2
  12. glaip_sdk/cli/display.py +35 -26
  13. glaip_sdk/cli/io.py +14 -5
  14. glaip_sdk/cli/main.py +185 -73
  15. glaip_sdk/cli/pager.py +2 -1
  16. glaip_sdk/cli/parsers/json_input.py +62 -14
  17. glaip_sdk/cli/resolution.py +4 -1
  18. glaip_sdk/cli/slash/__init__.py +3 -4
  19. glaip_sdk/cli/slash/agent_session.py +88 -36
  20. glaip_sdk/cli/slash/prompt.py +20 -48
  21. glaip_sdk/cli/slash/session.py +440 -189
  22. glaip_sdk/cli/transcript/__init__.py +71 -0
  23. glaip_sdk/cli/transcript/cache.py +338 -0
  24. glaip_sdk/cli/transcript/capture.py +278 -0
  25. glaip_sdk/cli/transcript/export.py +38 -0
  26. glaip_sdk/cli/transcript/launcher.py +79 -0
  27. glaip_sdk/cli/transcript/viewer.py +624 -0
  28. glaip_sdk/cli/update_notifier.py +29 -5
  29. glaip_sdk/cli/utils.py +256 -74
  30. glaip_sdk/client/agents.py +3 -1
  31. glaip_sdk/client/run_rendering.py +2 -2
  32. glaip_sdk/icons.py +19 -0
  33. glaip_sdk/models.py +6 -0
  34. glaip_sdk/rich_components.py +29 -1
  35. glaip_sdk/utils/__init__.py +1 -1
  36. glaip_sdk/utils/client_utils.py +6 -4
  37. glaip_sdk/utils/display.py +61 -32
  38. glaip_sdk/utils/rendering/formatting.py +6 -5
  39. glaip_sdk/utils/rendering/renderer/base.py +213 -66
  40. glaip_sdk/utils/rendering/renderer/debug.py +73 -16
  41. glaip_sdk/utils/rendering/renderer/panels.py +27 -15
  42. glaip_sdk/utils/rendering/renderer/progress.py +61 -38
  43. glaip_sdk/utils/serialization.py +5 -2
  44. glaip_sdk/utils/validation.py +1 -2
  45. {glaip_sdk-0.0.18.dist-info → glaip_sdk-0.0.20.dist-info}/METADATA +1 -1
  46. glaip_sdk-0.0.20.dist-info/RECORD +80 -0
  47. glaip_sdk/utils/rich_utils.py +0 -29
  48. glaip_sdk-0.0.18.dist-info/RECORD +0 -73
  49. {glaip_sdk-0.0.18.dist-info → glaip_sdk-0.0.20.dist-info}/WHEEL +0 -0
  50. {glaip_sdk-0.0.18.dist-info → glaip_sdk-0.0.20.dist-info}/entry_points.txt +0 -0
@@ -12,10 +12,20 @@ from rich.text import Text
12
12
 
13
13
  from glaip_sdk import Client
14
14
  from glaip_sdk._version import __version__ as _SDK_VERSION
15
- from glaip_sdk.branding import AIPBranding
15
+ from glaip_sdk.branding import (
16
+ ACCENT_STYLE,
17
+ ERROR_STYLE,
18
+ INFO,
19
+ PRIMARY,
20
+ SUCCESS,
21
+ SUCCESS_STYLE,
22
+ WARNING_STYLE,
23
+ AIPBranding,
24
+ )
16
25
  from glaip_sdk.cli.config import CONFIG_FILE, load_config, save_config
17
26
  from glaip_sdk.cli.rich_helpers import markup_text
18
- from glaip_sdk.cli.utils import command_hint
27
+ from glaip_sdk.cli.utils import command_hint, format_command_hint
28
+ from glaip_sdk.icons import ICON_TOOL
19
29
  from glaip_sdk.rich_components import AIPTable
20
30
 
21
31
  console = Console()
@@ -33,29 +43,10 @@ def list_config() -> None:
33
43
  config = load_config()
34
44
 
35
45
  if not config:
36
- hint = command_hint("config configure", slash_command="login")
37
- if hint:
38
- console.print(
39
- f"[yellow]No configuration found. Run '{hint}' to set up.[/yellow]"
40
- )
41
- else:
42
- console.print("[yellow]No configuration found.[/yellow]")
46
+ _print_missing_config_hint()
43
47
  return
44
48
 
45
- table = AIPTable(title="🔧 AIP Configuration")
46
- table.add_column("Setting", style="cyan", width=20)
47
- table.add_column("Value", style="green")
48
-
49
- for key, value in config.items():
50
- if key == "api_key" and value:
51
- # Mask the API key
52
- masked_value = "***" + value[-4:] if len(value) > 4 else "***"
53
- table.add_row(key, masked_value)
54
- else:
55
- table.add_row(key, str(value))
56
-
57
- console.print(table)
58
- console.print(Text(f"\n📁 Config file: {CONFIG_FILE}"))
49
+ _render_config_table(config)
59
50
 
60
51
 
61
52
  @config_group.command("set")
@@ -67,7 +58,7 @@ def set_config(key: str, value: str) -> None:
67
58
 
68
59
  if key not in valid_keys:
69
60
  console.print(
70
- f"[red]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/red]"
61
+ f"[{ERROR_STYLE}]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/]"
71
62
  )
72
63
  raise click.ClickException(f"Invalid configuration key: {key}")
73
64
 
@@ -76,10 +67,11 @@ def set_config(key: str, value: str) -> None:
76
67
  save_config(config)
77
68
 
78
69
  if key == "api_key":
79
- masked_value = "***" + value[-4:] if len(value) > 4 else "***"
80
- console.print(Text(f"✅ Set {key} = {masked_value}"))
70
+ console.print(
71
+ Text(f"✅ Set {key} = {_mask_api_key(value)}", style=SUCCESS_STYLE)
72
+ )
81
73
  else:
82
- console.print(Text(f"✅ Set {key} = {value}"))
74
+ console.print(Text(f"✅ Set {key} = {value}", style=SUCCESS_STYLE))
83
75
 
84
76
 
85
77
  @config_group.command("get")
@@ -90,16 +82,14 @@ def get_config(key: str) -> None:
90
82
 
91
83
  if key not in config:
92
84
  console.print(
93
- markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
85
+ markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]")
94
86
  )
95
87
  raise click.ClickException(f"Configuration key not found: {key}")
96
88
 
97
89
  value = config[key]
98
90
 
99
91
  if key == "api_key":
100
- # Mask the API key for display
101
- masked_value = "***" + value[-4:] if len(value) > 4 else "***"
102
- console.print(masked_value)
92
+ console.print(_mask_api_key(value))
103
93
  else:
104
94
  console.print(value)
105
95
 
@@ -112,14 +102,14 @@ def unset_config(key: str) -> None:
112
102
 
113
103
  if key not in config:
114
104
  console.print(
115
- markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
105
+ markup_text(f"[{WARNING_STYLE}]Configuration key '{key}' not found.[/]")
116
106
  )
117
107
  return
118
108
 
119
109
  del config[key]
120
110
  save_config(config)
121
111
 
122
- console.print(Text(f"✅ Removed {key} from configuration"))
112
+ console.print(Text(f"✅ Removed {key} from configuration", style=SUCCESS_STYLE))
123
113
 
124
114
 
125
115
  @config_group.command("reset")
@@ -127,7 +117,7 @@ def unset_config(key: str) -> None:
127
117
  def reset_config(force: bool) -> None:
128
118
  """Reset all configuration to defaults."""
129
119
  if not force:
130
- console.print("[yellow]This will remove all AIP configuration.[/yellow]")
120
+ console.print(f"[{WARNING_STYLE}]This will remove all AIP configuration.[/]")
131
121
  confirm = input("Are you sure? (y/N): ").strip().lower()
132
122
  if confirm not in ["y", "yes"]:
133
123
  console.print("Cancelled.")
@@ -137,8 +127,10 @@ def reset_config(force: bool) -> None:
137
127
  file_exists = CONFIG_FILE.exists()
138
128
 
139
129
  if not file_exists and not config_data:
140
- console.print("[yellow]No configuration found to reset.[/yellow]")
141
- console.print("✅ Configuration reset (nothing to remove).")
130
+ console.print(f"[{WARNING_STYLE}]No configuration found to reset.[/]")
131
+ console.print(
132
+ Text("✅ Configuration reset (nothing to remove).", style=SUCCESS_STYLE)
133
+ )
142
134
  return
143
135
 
144
136
  if file_exists:
@@ -151,103 +143,162 @@ def reset_config(force: bool) -> None:
151
143
  save_config({})
152
144
 
153
145
  hint = command_hint("config configure", slash_command="login")
154
- message = "✅ Configuration reset."
146
+ message = Text("✅ Configuration reset.", style=SUCCESS_STYLE)
155
147
  if hint:
156
- message += f" Run '{hint}' to set up again."
148
+ message.append(f" Run '{hint}' to set up again.")
157
149
  console.print(message)
158
150
 
159
151
 
160
152
  def _configure_interactive() -> None:
161
153
  """Shared configuration logic for both configure commands."""
162
- # Display AIP welcome banner
154
+ _render_configuration_header()
155
+ config = load_config()
156
+ _prompt_configuration_inputs(config)
157
+ _save_configuration(config)
158
+ _test_and_report_connection(config)
159
+ _print_post_configuration_hints()
160
+
161
+
162
+ @config_group.command()
163
+ def configure() -> None:
164
+ """Configure AIP CLI credentials and settings interactively."""
165
+ _configure_interactive()
166
+
167
+
168
+ # Alias command for backward compatibility
169
+ @click.command()
170
+ def configure_command() -> None:
171
+ """Configure AIP CLI credentials and settings interactively.
172
+
173
+ This is an alias for 'aip config configure' for backward compatibility.
174
+ """
175
+ # Delegate to the shared function
176
+ _configure_interactive()
177
+
178
+
179
+ # Note: The config command group should be registered in main.py
180
+
181
+
182
+ def _mask_api_key(value: str | None) -> str:
183
+ if not value:
184
+ return ""
185
+ return "***" + value[-4:] if len(value) > 4 else "***"
186
+
187
+
188
+ def _print_missing_config_hint() -> None:
189
+ hint = command_hint("config configure", slash_command="login")
190
+ if hint:
191
+ console.print(
192
+ f"[{WARNING_STYLE}]No configuration found.[/] Run {format_command_hint(hint) or hint} to set up."
193
+ )
194
+ else:
195
+ console.print(f"[{WARNING_STYLE}]No configuration found.[/]")
196
+
197
+
198
+ def _render_config_table(config: dict[str, str]) -> None:
199
+ table = AIPTable(title=f"{ICON_TOOL} AIP Configuration")
200
+ table.add_column("Setting", style=INFO, width=20)
201
+ table.add_column("Value", style=SUCCESS)
202
+
203
+ for key, value in config.items():
204
+ table.add_row(key, _mask_api_key(value) if key == "api_key" else str(value))
205
+
206
+ console.print(table)
207
+ console.print(Text(f"\n📁 Config file: {CONFIG_FILE}"))
208
+
209
+
210
+ def _render_configuration_header() -> None:
163
211
  branding = AIPBranding.create_from_sdk(
164
212
  sdk_version=_SDK_VERSION, package_name="glaip-sdk"
165
213
  )
166
- branding.display_welcome_panel(title="🔧 AIP Configuration")
214
+ heading = "[bold]>_ GDP Labs AI Agents Package (AIP CLI)[/bold]"
215
+ console.print(heading)
216
+ console.print()
217
+ console.print(branding.get_welcome_banner())
218
+ console.rule("[bold]AIP Configuration[/bold]", style=PRIMARY)
167
219
 
168
- # Load existing config
169
- config = load_config()
170
220
 
221
+ def _prompt_configuration_inputs(config: dict[str, str]) -> None:
171
222
  console.print("\n[bold]Enter your AIP configuration:[/bold]")
172
223
  console.print("(Leave blank to keep current values)")
173
224
  console.print("─" * 50)
174
225
 
175
- # API URL
226
+ _prompt_api_url(config)
227
+ _prompt_api_key(config)
228
+
229
+
230
+ def _prompt_api_url(config: dict[str, str]) -> None:
176
231
  current_url = config.get("api_url", "")
177
- console.print(
178
- f"\n[cyan]AIP API URL[/cyan] {f'(current: {current_url})' if current_url else ''}:"
179
- )
232
+ suffix = f"(current: {current_url})" if current_url else ""
233
+ console.print(f"\n[{ACCENT_STYLE}]AIP API URL[/] {suffix}:")
180
234
  new_url = input("> ").strip()
181
235
  if new_url:
182
236
  config["api_url"] = new_url
183
237
  elif not current_url:
184
238
  config["api_url"] = "https://your-aip-instance.com"
185
239
 
186
- # API Key
187
- current_key_masked = (
188
- "***" + config.get("api_key", "")[-4:] if config.get("api_key") else ""
189
- )
190
- console.print(
191
- f"\n[cyan]AIP API Key[/cyan] {f'(current: {current_key_masked})' if current_key_masked else ''}:"
192
- )
240
+
241
+ def _prompt_api_key(config: dict[str, str]) -> None:
242
+ current_key_masked = _mask_api_key(config.get("api_key"))
243
+ suffix = f"(current: {current_key_masked})" if current_key_masked else ""
244
+ console.print(f"\n[{ACCENT_STYLE}]AIP API Key[/] {suffix}:")
193
245
  new_key = getpass.getpass("> ")
194
246
  if new_key:
195
247
  config["api_key"] = new_key
196
248
 
197
- # Save configuration
249
+
250
+ def _save_configuration(config: dict[str, str]) -> None:
198
251
  save_config(config)
252
+ console.print(
253
+ Text(f"\n✅ Configuration saved to: {CONFIG_FILE}", style=SUCCESS_STYLE)
254
+ )
199
255
 
200
- console.print(Text(f"\n✅ Configuration saved to: {CONFIG_FILE}"))
201
256
 
202
- # Test the new configuration
257
+ def _test_and_report_connection(config: dict[str, str]) -> None:
203
258
  console.print("\n🔌 Testing connection...")
259
+ client: Client | None = None
204
260
  try:
205
- # Create client with new config
206
261
  client = Client(api_url=config["api_url"], api_key=config["api_key"])
207
-
208
- # Try to list resources to test connection
209
262
  try:
210
263
  agents = client.list_agents()
211
- console.print(Text(f"✅ Connection successful! Found {len(agents)} agents"))
212
- except Exception as e:
213
- console.print(Text(f"⚠️ Connection established but API call failed: {e}"))
264
+ console.print(
265
+ Text(
266
+ f"Connection successful! Found {len(agents)} agents",
267
+ style=SUCCESS_STYLE,
268
+ )
269
+ )
270
+ except Exception as exc: # pragma: no cover - API failures depend on network
271
+ console.print(
272
+ Text(
273
+ f"⚠️ Connection established but API call failed: {exc}",
274
+ style=WARNING_STYLE,
275
+ )
276
+ )
214
277
  console.print(
215
278
  " You may need to check your API permissions or network access"
216
279
  )
217
-
218
- client.close()
219
-
220
- except Exception as e:
221
- console.print(Text(f"❌ Connection failed: {e}"))
280
+ except Exception as exc:
281
+ console.print(Text(f"❌ Connection failed: {exc}"))
222
282
  console.print(" Please check your API URL and key")
223
283
  hint_status = command_hint("status", slash_command="status")
224
284
  if hint_status:
225
- console.print(f" You can run '{hint_status}' later to test again")
285
+ console.print(
286
+ f" You can run {format_command_hint(hint_status) or hint_status} later to test again"
287
+ )
288
+ finally:
289
+ if client is not None:
290
+ client.close()
291
+
226
292
 
293
+ def _print_post_configuration_hints() -> None:
227
294
  console.print("\n💡 You can now use AIP CLI commands!")
228
295
  hint_status = command_hint("status", slash_command="status")
229
296
  if hint_status:
230
- console.print(f" • Run '{hint_status}' to check connection")
297
+ console.print(
298
+ f" • Run {format_command_hint(hint_status) or hint_status} to check connection"
299
+ )
231
300
  hint_agents = command_hint("agents list", slash_command="agents")
232
301
  if hint_agents:
233
- console.print(f" • Run '{hint_agents}' to see your agents")
234
-
235
-
236
- @config_group.command()
237
- def configure() -> None:
238
- """Configure AIP CLI credentials and settings interactively."""
239
- _configure_interactive()
240
-
241
-
242
- # Alias command for backward compatibility
243
- @click.command()
244
- def configure_command() -> None:
245
- """Configure AIP CLI credentials and settings interactively.
246
-
247
- This is an alias for 'aip config configure' for backward compatibility.
248
- """
249
- # Delegate to the shared function
250
- _configure_interactive()
251
-
252
-
253
- # Note: The config command group should be registered in main.py
302
+ console.print(
303
+ f" • Run {format_command_hint(hint_agents) or hint_agents} to see your agents"
304
+ )