glaip-sdk 0.0.2__py3-none-any.whl → 0.0.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 (39) hide show
  1. glaip_sdk/__init__.py +2 -2
  2. glaip_sdk/_version.py +51 -0
  3. glaip_sdk/cli/commands/agents.py +201 -109
  4. glaip_sdk/cli/commands/configure.py +29 -87
  5. glaip_sdk/cli/commands/init.py +16 -7
  6. glaip_sdk/cli/commands/mcps.py +73 -153
  7. glaip_sdk/cli/commands/tools.py +185 -49
  8. glaip_sdk/cli/main.py +30 -27
  9. glaip_sdk/cli/utils.py +126 -13
  10. glaip_sdk/client/__init__.py +54 -2
  11. glaip_sdk/client/agents.py +175 -237
  12. glaip_sdk/client/base.py +62 -2
  13. glaip_sdk/client/mcps.py +63 -20
  14. glaip_sdk/client/tools.py +95 -28
  15. glaip_sdk/config/constants.py +10 -3
  16. glaip_sdk/exceptions.py +13 -0
  17. glaip_sdk/models.py +20 -4
  18. glaip_sdk/utils/__init__.py +116 -18
  19. glaip_sdk/utils/client_utils.py +284 -0
  20. glaip_sdk/utils/rendering/__init__.py +1 -0
  21. glaip_sdk/utils/rendering/formatting.py +211 -0
  22. glaip_sdk/utils/rendering/models.py +53 -0
  23. glaip_sdk/utils/rendering/renderer/__init__.py +38 -0
  24. glaip_sdk/utils/rendering/renderer/base.py +827 -0
  25. glaip_sdk/utils/rendering/renderer/config.py +33 -0
  26. glaip_sdk/utils/rendering/renderer/console.py +54 -0
  27. glaip_sdk/utils/rendering/renderer/debug.py +82 -0
  28. glaip_sdk/utils/rendering/renderer/panels.py +123 -0
  29. glaip_sdk/utils/rendering/renderer/progress.py +118 -0
  30. glaip_sdk/utils/rendering/renderer/stream.py +198 -0
  31. glaip_sdk/utils/rendering/steps.py +168 -0
  32. glaip_sdk/utils/run_renderer.py +22 -1086
  33. {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.3.dist-info}/METADATA +8 -36
  34. glaip_sdk-0.0.3.dist-info/RECORD +40 -0
  35. glaip_sdk/cli/config.py +0 -592
  36. glaip_sdk/utils.py +0 -167
  37. glaip_sdk-0.0.2.dist-info/RECORD +0 -28
  38. {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.3.dist-info}/WHEEL +0 -0
  39. {glaip_sdk-0.0.2.dist-info → glaip_sdk-0.0.3.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glaip-sdk
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Python SDK for AI Agent Platform - Simplified CLI Design
5
5
  Author-email: Raymond Christopher <raymond.christopher@gdplabs.id>
6
6
  License: MIT
@@ -545,44 +545,16 @@ make test-integration
545
545
  make pre-commit
546
546
  ```
547
547
 
548
- ### Version Management
548
+ ### Versioning
549
549
 
550
- The project uses `bump2version` for automated version management. This ensures all version references are updated consistently across the codebase.
550
+ Single source of truth: `pyproject.toml` under `[project].version`.
551
551
 
552
- #### Quick Version Bumps
552
+ The SDK resolves its runtime version from installed package metadata
553
+ (`glaip_sdk/_version.py`), so you do not need to edit any code files when
554
+ changing the version. Update once in `pyproject.toml`, then build/reinstall.
553
555
 
554
- ```bash
555
- # Bump patch version (0.1.0 → 0.1.1) - for bug fixes
556
- python scripts/bump_version.py patch
557
-
558
- # Bump minor version (0.1.0 → 0.2.0) - for new features
559
- python scripts/bump_version.py minor
560
-
561
- # Bump major version (0.1.0 → 1.0.0) - for breaking changes
562
- python scripts/bump_version.py major
563
-
564
- # Preview changes without making them
565
- python scripts/bump_version.py --dry-run patch
566
- ```
567
-
568
- #### What Gets Updated
569
-
570
- The following files are automatically updated when bumping versions:
571
- - `pyproject.toml` - Package version
572
- - `glaip_sdk/__init__.py` - Module version
573
- - `glaip_sdk/cli/main.py` - CLI version display
574
- - `glaip_sdk/config/constants.py` - SDK version constant
575
- - `examples/__init__.py` - Examples version
576
-
577
- #### After Version Bump
578
-
579
- ```bash
580
- # Push changes and tags
581
- git push --follow-tags
582
-
583
- # Create GitHub release for the new version
584
- # (GitHub releases will automatically use the git tag)
585
- ```
556
+ Release by tagging (e.g., `v0.0.3`) and creating a GitHub Release that
557
+ matches the tag.
586
558
 
587
559
  ---
588
560
 
@@ -0,0 +1,40 @@
1
+ glaip_sdk/__init__.py,sha256=UGBsYHHSgSc1HGCTsA9bbz2ARJJ1g49cTieXEINHtAk,323
2
+ glaip_sdk/_version.py,sha256=Rb9YLDvK1DXCVFrjlLDbtucpwKh_PyCnmZ-ia9VX3Cc,1650
3
+ glaip_sdk/exceptions.py,sha256=QTVtwxRHMN4e8gGn0icXphZvdugiRvcSrlMYylwGsDc,1993
4
+ glaip_sdk/models.py,sha256=i_MumCH0PvqEJLsUrGm7vkytxnhsJ3YtWq2y6H-JVzQ,7235
5
+ glaip_sdk/cli/__init__.py,sha256=cPI-uOOBww_ESiH6NQBdJiTg8CUVNigFOU3kl0tgTuI,143
6
+ glaip_sdk/cli/main.py,sha256=Xx7kNbnWV--oLh-DxfR94a2rGecziwi_JHIFkwEqj70,10133
7
+ glaip_sdk/cli/utils.py,sha256=PeVsG84-i1UbX-ETDUPrrLuismRQZTJLQdBvOqWia6Q,25540
8
+ glaip_sdk/cli/commands/__init__.py,sha256=WShiuYqHcbuexPboibDJ_Q2jOPIWp-TgsyUAO2-T20I,134
9
+ glaip_sdk/cli/commands/agents.py,sha256=5-bhSo_lXFhhpJRAPd9Z0lxQq4Yg_OImRBVwk-debko,17331
10
+ glaip_sdk/cli/commands/configure.py,sha256=2MDQ5Q-Rrd7T3eO8ThKJZz_B3-Gqp3UFKk-rrnmPPvk,7135
11
+ glaip_sdk/cli/commands/init.py,sha256=Er8UH2aMpnLJ9aiSBOfp26__G1ll5L7W-CYaiHpats8,5778
12
+ glaip_sdk/cli/commands/mcps.py,sha256=09KlY9ICjinuTkZvLKDsyOT3Ahz4zk_LJPZqhJrc9Lk,11956
13
+ glaip_sdk/cli/commands/models.py,sha256=j8VqQ2edSEvD-sQXWm8ifUco9gX8J-OBib6OvzthpqU,1405
14
+ glaip_sdk/cli/commands/tools.py,sha256=0YVJ7Z4g5Saor2M0jCp2B2BzkgfVaE5Wr4S-7oSpV6U,14397
15
+ glaip_sdk/client/__init__.py,sha256=jnsD3HCiOGiuL_4aqJiVnBsF8HNFS-s_aNLfg26gJqs,7530
16
+ glaip_sdk/client/agents.py,sha256=PF-4HF2gx8E3uA5Xx6rQcEzKI9svaYgJPBuO8Ze-wdQ,14000
17
+ glaip_sdk/client/base.py,sha256=3Ri5GVYrZ4cZ5lex1pyG0nvEmGxeXwAY194MxSH1_cY,9463
18
+ glaip_sdk/client/mcps.py,sha256=UEwgFbl4ogeozfJGcUbQQ7JGfwYliN9i5V6fTvkbOZ0,4311
19
+ glaip_sdk/client/tools.py,sha256=RMSDFeaV0u_iE331d66hkinz4a1_GWfBRbyrOEejvYA,8610
20
+ glaip_sdk/client/validators.py,sha256=3MtOt11IivEwQAgzmdRGWUBzP223ytECOLU_a77x7IU,7101
21
+ glaip_sdk/config/constants.py,sha256=Pm0tGYiJ9VdW9XXz0CG36l8-sAhnlFPTKbHKKleUgik,705
22
+ glaip_sdk/utils/__init__.py,sha256=5pOPBTjJ4hzvMNYjLnTut_ovwU8QJ39kARKx9-qr5Qs,5101
23
+ glaip_sdk/utils/client_utils.py,sha256=O44OlbQD4X0cMo_3E_Ysb_XyfEG20v0wecl5SlM9kxo,9407
24
+ glaip_sdk/utils/run_renderer.py,sha256=JGQzXymsptgr927-F49H1AOT5bzqErDXZMF2pOxqbfw,1365
25
+ glaip_sdk/utils/rendering/__init__.py,sha256=vXjwk5rPhhfPyD8S0DnV4GFFEtPJp4HCCg1Um9SXfs0,70
26
+ glaip_sdk/utils/rendering/formatting.py,sha256=HPCBcpWP3EpSXsIgfm-uWm6Fjo6VWzqxrnhEc137wjA,6941
27
+ glaip_sdk/utils/rendering/models.py,sha256=ffPMv4XrKY4V2-THL69KONZf1NL7msIa-jVZAVuz2Js,1559
28
+ glaip_sdk/utils/rendering/steps.py,sha256=qx6aNhfYYAbcXaHws-zdHOc4Yw3me3Cd19SZkZluJvg,5837
29
+ glaip_sdk/utils/rendering/renderer/__init__.py,sha256=kZwCYRcQdK-9sfZPxAAqLB--A2icLbSKq7AW1_NIIGQ,987
30
+ glaip_sdk/utils/rendering/renderer/base.py,sha256=IRQMNW4WHPRpBFXfXuHSo8oOWi4-Tn1_hF9a9x0_q3c,32288
31
+ glaip_sdk/utils/rendering/renderer/config.py,sha256=E4ER8TJJbqr1hcWjkwG7XROqLuccQy4EL99CbuLvSXE,783
32
+ glaip_sdk/utils/rendering/renderer/console.py,sha256=ibQU07rmrWw-MMX6n3J2ewxuOEY-Z6RnKEfzMH2-IrA,1744
33
+ glaip_sdk/utils/rendering/renderer/debug.py,sha256=2XP6A4w3EIjVVY_M-BDPvHf05QQSz0TDTo-dRPf1fSc,2862
34
+ glaip_sdk/utils/rendering/renderer/panels.py,sha256=iTDJoRBaa73pX9z9nTcb6aKhfXe1Mds0RzCuhwtvkdc,2994
35
+ glaip_sdk/utils/rendering/renderer/progress.py,sha256=i4HG_iNwtK4c3Gf2sviLCiOJ-5ydX4t-YE5dgtLOxNI,3438
36
+ glaip_sdk/utils/rendering/renderer/stream.py,sha256=ZKitYkt_7OirNeERu3cc_NybQ8mWUMoEstg9UL1S090,7323
37
+ glaip_sdk-0.0.3.dist-info/METADATA,sha256=Rtei3FvfrthFvPqL3t1biMy6zvxiwAsCyJi_iB-6KHk,19501
38
+ glaip_sdk-0.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
39
+ glaip_sdk-0.0.3.dist-info/entry_points.txt,sha256=65vNPUggyYnVGhuw7RhNJ8Fp2jygTcX0yxJBcBY3iLU,48
40
+ glaip_sdk-0.0.3.dist-info/RECORD,,
glaip_sdk/cli/config.py DELETED
@@ -1,592 +0,0 @@
1
- """CLI commands for managing SDK configuration.
2
-
3
- Authors:
4
- Raymond Christopher (raymond.christopher@gdplabs.id)
5
- """
6
-
7
- import json
8
- import os
9
- from pathlib import Path
10
-
11
- import click
12
-
13
- from glaip_sdk import Client
14
-
15
-
16
- def get_client(ctx) -> Client:
17
- """Get configured client from context."""
18
- config = ctx.obj or {}
19
- return Client(
20
- api_url=config.get("api_url"),
21
- api_key=config.get("api_key"),
22
- timeout=config.get("timeout", 30.0),
23
- )
24
-
25
-
26
- @click.group()
27
- def config_group():
28
- """Manage SDK configuration."""
29
- pass
30
-
31
-
32
- @config_group.command()
33
- @click.pass_context
34
- def show(ctx):
35
- """Show current configuration."""
36
- try:
37
- # Get config from context
38
- context_config = ctx.obj or {}
39
-
40
- # Get config from environment
41
- env_config = {
42
- "api_url": os.getenv("AIP_API_URL"),
43
- "api_key": os.getenv("AIP_API_KEY"),
44
- "timeout": os.getenv("AIP_TIMEOUT", "30.0"),
45
- }
46
-
47
- # Get config from file
48
- config_path = Path.home() / ".aip" / "config.yaml"
49
- file_config = {}
50
- if config_path.exists():
51
- try:
52
- import yaml
53
-
54
- with open(config_path) as f:
55
- file_config = yaml.safe_load(f) or {}
56
- except Exception:
57
- file_config = {}
58
-
59
- click.echo("🔧 AIP SDK Configuration")
60
- click.echo("=" * 50)
61
-
62
- # Show configuration sources
63
- click.echo("Configuration Sources (in order of precedence):")
64
- click.echo(" 1. Command line arguments")
65
- click.echo(" 2. Environment variables")
66
- click.echo(" 3. Config file (~/.aip/config.yaml)")
67
- click.echo(" 4. Default values")
68
- click.echo()
69
-
70
- # Show current values
71
- click.echo("Current Configuration:")
72
- click.echo(
73
- f" API URL: {context_config.get('api_url') or env_config['api_url'] or file_config.get('api_url') or 'Not set'}"
74
- )
75
-
76
- api_key = (
77
- context_config.get("api_key")
78
- or env_config["api_key"]
79
- or file_config.get("api_key")
80
- )
81
- if api_key:
82
- # Mask API key for security
83
- masked_key = (
84
- api_key[:8] + "..." + api_key[-4:] if len(api_key) > 12 else "***"
85
- )
86
- click.echo(f" API Key: {masked_key}")
87
- else:
88
- click.echo(" API Key: Not set")
89
-
90
- timeout = (
91
- context_config.get("timeout")
92
- or env_config["timeout"]
93
- or file_config.get("timeout")
94
- or "30.0"
95
- )
96
- click.echo(f" Timeout: {timeout} seconds")
97
-
98
- # Show config file location
99
- click.echo(f"\nConfig file: {config_path}")
100
- if config_path.exists():
101
- click.echo("✅ Config file exists")
102
- else:
103
- click.echo("❌ Config file does not exist")
104
-
105
- except Exception as e:
106
- click.echo(f"❌ Error showing configuration: {e}")
107
-
108
-
109
- @config_group.command()
110
- @click.option("--api-url", help="Set API URL")
111
- @click.option("--api-key", help="Set API key")
112
- @click.option("--timeout", type=float, help="Set timeout in seconds")
113
- @click.option("--output", "-o", type=click.Path(), help="Output file for configuration")
114
- @click.pass_context
115
- def set(ctx, api_url, api_key, timeout, output):
116
- """Set configuration values."""
117
- try:
118
- # Get current config
119
- config_path = Path.home() / ".aip" / "config.yaml"
120
- config_path.parent.mkdir(parents=True, exist_ok=True)
121
-
122
- # Load existing config
123
- current_config = {}
124
- if config_path.exists():
125
- try:
126
- import yaml
127
-
128
- with open(config_path) as f:
129
- current_config = yaml.safe_load(f) or {}
130
- except Exception:
131
- current_config = {}
132
-
133
- # Update config with new values
134
- updated = False
135
- if api_url:
136
- current_config["api_url"] = api_url
137
- updated = True
138
- click.echo(f"✅ API URL set to: {api_url}")
139
-
140
- if api_key:
141
- current_config["api_key"] = api_key
142
- updated = True
143
- # Mask API key for display
144
- masked_key = (
145
- api_key[:8] + "..." + api_key[-4:] if len(api_key) > 12 else "***"
146
- )
147
- click.echo(f"✅ API Key set to: {masked_key}")
148
-
149
- if timeout:
150
- current_config["timeout"] = timeout
151
- updated = True
152
- click.echo(f"✅ Timeout set to: {timeout} seconds")
153
-
154
- if not updated:
155
- click.echo(
156
- "❌ No configuration values provided. Use --help for available options."
157
- )
158
- return
159
-
160
- # Save updated config
161
- try:
162
- import yaml
163
-
164
- with open(config_path, "w") as f:
165
- yaml.dump(current_config, f, default_flow_style=False)
166
- click.echo(f"📄 Configuration saved to: {config_path}")
167
- except Exception as e:
168
- click.echo(f"❌ Error saving configuration: {e}")
169
- return
170
-
171
- # Save to output file if specified
172
- if output:
173
- output_path = Path(output)
174
- with open(output_path, "w") as f:
175
- json.dump(current_config, f, indent=2, default=str)
176
- click.echo(f"📄 Configuration also saved to: {output_path}")
177
-
178
- except Exception as e:
179
- click.echo(f"❌ Error setting configuration: {e}")
180
-
181
-
182
- @config_group.command()
183
- @click.option("--api-url", is_flag=True, help="Remove API URL setting")
184
- @click.option("--api-key", is_flag=True, help="Remove API key setting")
185
- @click.option("--timeout", is_flag=True, help="Remove timeout setting")
186
- @click.option("--all", is_flag=True, help="Remove all configuration")
187
- @click.option(
188
- "--output", "-o", type=click.Path(), help="Output file for remaining configuration"
189
- )
190
- @click.pass_context
191
- def unset(ctx, api_url, api_key, timeout, all, output):
192
- """Remove configuration values."""
193
- try:
194
- # Get current config
195
- config_path = Path.home() / ".aip" / "config.yaml"
196
-
197
- if not config_path.exists():
198
- click.echo("❌ No configuration file found.")
199
- return
200
-
201
- # Load current config
202
- try:
203
- import yaml
204
-
205
- with open(config_path) as f:
206
- current_config = yaml.safe_load(f) or {}
207
- except Exception as e:
208
- click.echo(f"❌ Error loading configuration: {e}")
209
- return
210
-
211
- # Remove specified values
212
- removed = False
213
- if all:
214
- # Remove all configuration
215
- current_config = {}
216
- removed = True
217
- click.echo("✅ All configuration removed")
218
- else:
219
- if api_url and "api_url" in current_config:
220
- del current_config["api_url"]
221
- removed = True
222
- click.echo("✅ API URL removed")
223
-
224
- if api_key and "api_key" in current_config:
225
- del current_config["api_key"]
226
- removed = True
227
- click.echo("✅ API Key removed")
228
-
229
- if timeout and "timeout" in current_config:
230
- del current_config["timeout"]
231
- removed = True
232
- click.echo("✅ Timeout removed")
233
-
234
- if not removed:
235
- click.echo(
236
- "❌ No configuration values specified for removal. Use --help for available options."
237
- )
238
- return
239
-
240
- # Save updated config
241
- if current_config:
242
- try:
243
- with open(config_path, "w") as f:
244
- yaml.dump(current_config, f, default_flow_style=False)
245
- click.echo(f"📄 Updated configuration saved to: {config_path}")
246
- except Exception as e:
247
- click.echo(f"❌ Error saving configuration: {e}")
248
- return
249
- else:
250
- # Remove config file if empty
251
- try:
252
- config_path.unlink()
253
- click.echo(f"📄 Configuration file removed: {config_path}")
254
- except Exception as e:
255
- click.echo(f"❌ Error removing configuration file: {e}")
256
- return
257
-
258
- # Save to output file if specified
259
- if output:
260
- output_path = Path(output)
261
- with open(output_path, "w") as f:
262
- json.dump(current_config, f, indent=2, default=str)
263
- click.echo(f"📄 Remaining configuration saved to: {output_path}")
264
-
265
- except Exception as e:
266
- click.echo(f"❌ Error removing configuration: {e}")
267
-
268
-
269
- @config_group.command()
270
- @click.option("--output", "-o", type=click.Path(), help="Output file for configuration")
271
- @click.pass_context
272
- def export(ctx, output):
273
- """Export current configuration."""
274
- try:
275
- # Get config from all sources
276
- config_path = Path.home() / ".aip" / "config.yaml"
277
-
278
- # Load file config
279
- file_config = {}
280
- if config_path.exists():
281
- try:
282
- import yaml
283
-
284
- with open(config_path) as f:
285
- file_config = yaml.safe_load(f) or {}
286
- except Exception:
287
- file_config = {}
288
-
289
- # Get environment config
290
- env_config = {
291
- "api_url": os.getenv("AIP_API_URL"),
292
- "api_key": os.getenv("AIP_API_KEY"),
293
- "timeout": os.getenv("AIP_TIMEOUT"),
294
- }
295
-
296
- # Combine configs (environment overrides file)
297
- combined_config = {**file_config, **env_config}
298
-
299
- # Remove None values
300
- combined_config = {k: v for k, v in combined_config.items() if v is not None}
301
-
302
- if not combined_config:
303
- click.echo("❌ No configuration found to export.")
304
- return
305
-
306
- # Display configuration
307
- click.echo("📤 Exported Configuration:")
308
- click.echo("=" * 30)
309
-
310
- for key, value in combined_config.items():
311
- if key == "api_key" and value:
312
- # Mask API key for display
313
- masked_value = (
314
- value[:8] + "..." + value[-4:] if len(value) > 12 else "***"
315
- )
316
- click.echo(f"{key}: {masked_value}")
317
- else:
318
- click.echo(f"{key}: {value}")
319
-
320
- # Save to output file if specified
321
- if output:
322
- output_path = Path(output)
323
- with open(output_path, "w") as f:
324
- json.dump(combined_config, f, indent=2, default=str)
325
- click.echo(f"\n📄 Configuration exported to: {output_path}")
326
- else:
327
- # Save to default location
328
- export_path = Path.home() / ".aip" / "config_export.json"
329
- export_path.parent.mkdir(parents=True, exist_ok=True)
330
- with open(export_path, "w") as f:
331
- json.dump(combined_config, f, indent=2, default=str)
332
- click.echo(f"\n📄 Configuration exported to: {export_path}")
333
-
334
- except Exception as e:
335
- click.echo(f"❌ Error exporting configuration: {e}")
336
-
337
-
338
- @config_group.command()
339
- @click.argument("config_file", type=click.Path(exists=True))
340
- @click.option("--overwrite", is_flag=True, help="Overwrite existing configuration")
341
- @click.option(
342
- "--output", "-o", type=click.Path(), help="Output file for imported configuration"
343
- )
344
- @click.pass_context
345
- def import_config(ctx, config_file, overwrite, output):
346
- """Import configuration from a file."""
347
- try:
348
- config_path = Path(config_file)
349
-
350
- # Load configuration from file
351
- try:
352
- if config_path.suffix.lower() in [".json", ".js"]:
353
- with open(config_path) as f:
354
- imported_config = json.load(f)
355
- elif config_path.suffix.lower() in [".yaml", ".yml"]:
356
- import yaml
357
-
358
- with open(config_path) as f:
359
- imported_config = yaml.safe_load(f)
360
- else:
361
- click.echo(f"❌ Unsupported file format: {config_path.suffix}")
362
- click.echo("Supported formats: .json, .yaml, .yml")
363
- return
364
- except Exception as e:
365
- click.echo(f"❌ Error loading configuration file: {e}")
366
- return
367
-
368
- if not imported_config:
369
- click.echo("❌ Configuration file is empty or invalid.")
370
- return
371
-
372
- # Get current config
373
- current_config_path = Path.home() / ".aip" / "config.yaml"
374
- current_config = {}
375
-
376
- if current_config_path.exists() and not overwrite:
377
- try:
378
- import yaml
379
-
380
- with open(current_config_path) as f:
381
- current_config = yaml.safe_load(f) or {}
382
- except Exception:
383
- current_config = {}
384
-
385
- # Merge configurations
386
- merged_config = {**current_config, **imported_config}
387
-
388
- # Save merged configuration
389
- current_config_path.parent.mkdir(parents=True, exist_ok=True)
390
- try:
391
- import yaml
392
-
393
- with open(current_config_path, "w") as f:
394
- yaml.dump(merged_config, f, default_flow_style=False)
395
- click.echo(f"✅ Configuration imported and saved to: {current_config_path}")
396
- except Exception as e:
397
- click.echo(f"❌ Error saving merged configuration: {e}")
398
- return
399
-
400
- # Display imported configuration
401
- click.echo("\n📥 Imported Configuration:")
402
- click.echo("=" * 30)
403
-
404
- for key, value in imported_config.items():
405
- if key == "api_key" and value:
406
- # Mask API key for display
407
- masked_value = (
408
- value[:8] + "..." + value[-4:] if len(value) > 12 else "***"
409
- )
410
- click.echo(f"{key}: {masked_value}")
411
- else:
412
- click.echo(f"{key}: {value}")
413
-
414
- # Save to output file if specified
415
- if output:
416
- output_path = Path(output)
417
- with open(output_path, "w") as f:
418
- json.dump(merged_config, f, indent=2, default=str)
419
- click.echo(f"\n📄 Merged configuration saved to: {output_path}")
420
-
421
- except Exception as e:
422
- click.echo(f"❌ Error importing configuration: {e}")
423
-
424
-
425
- @config_group.command()
426
- @click.pass_context
427
- def validate(ctx):
428
- """Validate current configuration."""
429
- try:
430
- # Get config from all sources
431
- config_path = Path.home() / ".aip" / "config.yaml"
432
-
433
- # Load file config
434
- file_config = {}
435
- if config_path.exists():
436
- try:
437
- import yaml
438
-
439
- with open(config_path) as f:
440
- file_config = yaml.safe_load(f) or {}
441
- except Exception as e:
442
- click.echo(f"❌ Error loading config file: {e}")
443
- file_config = {}
444
-
445
- # Get environment config
446
- env_config = {
447
- "api_url": os.getenv("AIP_API_URL"),
448
- "api_key": os.getenv("AIP_API_KEY"),
449
- "timeout": os.getenv("AIP_TIMEOUT"),
450
- }
451
-
452
- # Combine configs (environment overrides file)
453
- combined_config = {**file_config, **env_config}
454
-
455
- # Remove None values
456
- combined_config = {k: v for k, v in combined_config.items() if v is not None}
457
-
458
- click.echo("🔍 Validating Configuration")
459
- click.echo("=" * 40)
460
-
461
- # Check required fields
462
- required_fields = ["api_url", "api_key"]
463
- missing_fields = []
464
-
465
- for field in required_fields:
466
- if field not in combined_config:
467
- missing_fields.append(field)
468
- else:
469
- click.echo(f"✅ {field}: Set")
470
-
471
- if missing_fields:
472
- click.echo(f"❌ Missing required fields: {', '.join(missing_fields)}")
473
- click.echo("\nTo set these values, use:")
474
- for field in missing_fields:
475
- if field == "api_url":
476
- click.echo(f" aip config set --{field} <your-api-url>")
477
- elif field == "api_key":
478
- click.echo(f" aip config set --{field} <your-api-key>")
479
- return
480
-
481
- # Validate API URL format
482
- api_url = combined_config["api_url"]
483
- if not api_url.startswith(("http://", "https://")):
484
- click.echo("⚠️ Warning: API URL should start with http:// or https://")
485
-
486
- # Validate timeout if present
487
- if "timeout" in combined_config:
488
- try:
489
- timeout = float(combined_config["timeout"])
490
- if timeout <= 0:
491
- click.echo(f"❌ Timeout must be positive, got: {timeout}")
492
- return
493
- click.echo(f"✅ timeout: {timeout} seconds")
494
- except ValueError:
495
- click.echo(f"❌ Invalid timeout value: {combined_config['timeout']}")
496
- return
497
-
498
- # Test connection if possible
499
- click.echo("\n🔌 Testing Connection...")
500
- try:
501
- client = Client(
502
- api_url=combined_config["api_url"],
503
- api_key=combined_config["api_key"],
504
- timeout=float(combined_config.get("timeout", 30.0)),
505
- )
506
-
507
- # Try to list resources to test connection
508
- try:
509
- agents = client.list_agents()
510
- click.echo(f"✅ Connection successful! Found {len(agents)} agents")
511
- except Exception as e:
512
- click.echo(f"⚠️ Connection established but API call failed: {e}")
513
-
514
- client.close()
515
-
516
- except Exception as e:
517
- click.echo(f"❌ Connection failed: {e}")
518
- return
519
-
520
- click.echo("\n🎉 Configuration is valid!")
521
-
522
- except Exception as e:
523
- click.echo(f"❌ Error validating configuration: {e}")
524
-
525
-
526
- @config_group.command()
527
- @click.pass_context
528
- def init(ctx):
529
- """Initialize configuration interactively."""
530
- try:
531
- click.echo("🚀 AIP SDK Configuration Initialization")
532
- click.echo("=" * 50)
533
- click.echo("This will help you set up your AIP SDK configuration.")
534
- click.echo()
535
-
536
- # Get configuration values interactively
537
- api_url = click.prompt(
538
- "Enter your AIP API URL", default="https://api.aiagentplatform.com"
539
- )
540
-
541
- api_key = click.prompt("Enter your AIP API Key", hide_input=True)
542
-
543
- timeout = click.prompt(
544
- "Enter request timeout in seconds", default=30.0, type=float
545
- )
546
-
547
- # Confirm configuration
548
- click.echo("\n📋 Configuration Summary:")
549
- click.echo(f" API URL: {api_url}")
550
- click.echo(
551
- f" API Key: {api_key[:8]}...{api_key[-4:] if len(api_key) > 12 else '***'}"
552
- )
553
- click.echo(f" Timeout: {timeout} seconds")
554
-
555
- if not click.confirm("\nIs this configuration correct?"):
556
- click.echo("Configuration cancelled.")
557
- return
558
-
559
- # Save configuration
560
- config_path = Path.home() / ".aip" / "config.yaml"
561
- config_path.parent.mkdir(parents=True, exist_ok=True)
562
-
563
- config_data = {"api_url": api_url, "api_key": api_key, "timeout": timeout}
564
-
565
- try:
566
- import yaml
567
-
568
- with open(config_path, "w") as f:
569
- yaml.dump(config_data, f, default_flow_style=False)
570
- click.echo(f"\n✅ Configuration saved to: {config_path}")
571
- except Exception as e:
572
- click.echo(f"❌ Error saving configuration: {e}")
573
- return
574
-
575
- # Test connection
576
- click.echo("\n🔌 Testing connection...")
577
- try:
578
- client = Client(api_url=api_url, api_key=api_key, timeout=timeout)
579
- agents = client.list_agents()
580
- click.echo(f"✅ Connection successful! Found {len(agents)} agents")
581
- client.close()
582
- except Exception as e:
583
- click.echo(f"⚠️ Configuration saved but connection test failed: {e}")
584
- click.echo(
585
- "You may need to check your API credentials or network connection."
586
- )
587
-
588
- click.echo("\n🎉 Configuration initialization complete!")
589
- click.echo("You can now use the AIP SDK CLI commands.")
590
-
591
- except Exception as e:
592
- click.echo(f"❌ Error during configuration initialization: {e}")