glaip-sdk 0.0.1b5__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.
@@ -0,0 +1,316 @@
1
+ """Configuration management commands.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ import getpass
8
+ import os
9
+ from pathlib import Path
10
+
11
+ import click
12
+ import yaml
13
+ from rich.console import Console
14
+ from rich.panel import Panel
15
+ from rich.table import Table
16
+
17
+ console = Console()
18
+
19
+ CONFIG_DIR = Path.home() / ".aip"
20
+ CONFIG_FILE = CONFIG_DIR / "config.yaml"
21
+
22
+
23
+ def load_config():
24
+ """Load configuration from file."""
25
+ if not CONFIG_FILE.exists():
26
+ return {}
27
+
28
+ with open(CONFIG_FILE) as f:
29
+ return yaml.safe_load(f) or {}
30
+
31
+
32
+ def save_config(config):
33
+ """Save configuration to file."""
34
+ CONFIG_DIR.mkdir(exist_ok=True)
35
+
36
+ with open(CONFIG_FILE, "w") as f:
37
+ yaml.dump(config, f, default_flow_style=False)
38
+
39
+ # Set secure file permissions
40
+ try:
41
+ os.chmod(CONFIG_FILE, 0o600)
42
+ except Exception:
43
+ pass # Best effort
44
+
45
+
46
+ @click.group()
47
+ def config_group():
48
+ """Configuration management operations."""
49
+ pass
50
+
51
+
52
+ @config_group.command()
53
+ def configure():
54
+ """Configure AIP CLI credentials and settings interactively."""
55
+
56
+ console.print(
57
+ Panel(
58
+ "[bold cyan]AIP Configuration[/bold cyan]\nConfigure your AIP CLI settings.",
59
+ title="šŸ”§ Configuration Setup",
60
+ border_style="cyan",
61
+ )
62
+ )
63
+
64
+ # Load existing config
65
+ config = load_config()
66
+
67
+ console.print("\n[bold]Enter your AIP configuration:[/bold]")
68
+ console.print("(Leave blank to keep current values)")
69
+ console.print("─" * 50)
70
+
71
+ # API URL
72
+ current_url = config.get("api_url", "")
73
+ console.print(
74
+ f"\n[cyan]AIP API URL[/cyan] {f'(current: {current_url})' if current_url else ''}:"
75
+ )
76
+ new_url = input("> ").strip()
77
+ if new_url:
78
+ config["api_url"] = new_url
79
+ elif not current_url:
80
+ config["api_url"] = "https://your-aip-instance.com"
81
+
82
+ # API Key
83
+ current_key_masked = (
84
+ "***" + config.get("api_key", "")[-4:] if config.get("api_key") else ""
85
+ )
86
+ console.print(
87
+ f"\n[cyan]AIP API Key[/cyan] {f'(current: {current_key_masked})' if current_key_masked else ''}:"
88
+ )
89
+ new_key = getpass.getpass("> ")
90
+ if new_key:
91
+ config["api_key"] = new_key
92
+
93
+ # Save configuration
94
+ save_config(config)
95
+
96
+ console.print(f"\nāœ… Configuration saved to: {CONFIG_FILE}")
97
+
98
+ # Test the new configuration
99
+ console.print("\nšŸ”Œ Testing connection...")
100
+ try:
101
+ from glaip_sdk import Client
102
+
103
+ # Create client with new config
104
+ client = Client(api_url=config["api_url"], api_key=config["api_key"])
105
+
106
+ # Try to list resources to test connection
107
+ try:
108
+ agents = client.list_agents()
109
+ console.print(f"āœ… Connection successful! Found {len(agents)} agents")
110
+ except Exception as e:
111
+ console.print(f"āš ļø Connection established but API call failed: {e}")
112
+ console.print(
113
+ " You may need to check your API permissions or network access"
114
+ )
115
+
116
+ client.close()
117
+
118
+ except Exception as e:
119
+ console.print(f"āŒ Connection failed: {e}")
120
+ console.print(" Please check your API URL and key")
121
+ console.print(" You can run 'aip status' later to test again")
122
+
123
+ console.print("\nšŸ’” You can now use AIP CLI commands!")
124
+ console.print(" • Run 'aip status' to check connection")
125
+ console.print(" • Run 'aip agents list' to see your agents")
126
+
127
+
128
+ @config_group.command("list")
129
+ def list_config():
130
+ """List current configuration."""
131
+
132
+ config = load_config()
133
+
134
+ if not config:
135
+ console.print(
136
+ "[yellow]No configuration found. Run 'aip config configure' to set up.[/yellow]"
137
+ )
138
+ return
139
+
140
+ table = Table(title="šŸ”§ AIP Configuration")
141
+ table.add_column("Setting", style="cyan", width=20)
142
+ table.add_column("Value", style="green")
143
+
144
+ for key, value in config.items():
145
+ if key == "api_key" and value:
146
+ # Mask the API key
147
+ masked_value = "***" + value[-4:] if len(value) > 4 else "***"
148
+ table.add_row(key, masked_value)
149
+ else:
150
+ table.add_row(key, str(value))
151
+
152
+ console.print(table)
153
+ console.print(f"\nšŸ“ Config file: {CONFIG_FILE}")
154
+
155
+
156
+ @config_group.command("set")
157
+ @click.argument("key")
158
+ @click.argument("value")
159
+ def set_config(key, value):
160
+ """Set a configuration value."""
161
+
162
+ valid_keys = ["api_url", "api_key"]
163
+
164
+ if key not in valid_keys:
165
+ console.print(
166
+ f"[red]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/red]"
167
+ )
168
+ raise click.ClickException(f"Invalid configuration key: {key}")
169
+
170
+ config = load_config()
171
+ config[key] = value
172
+ save_config(config)
173
+
174
+ if key == "api_key":
175
+ masked_value = "***" + value[-4:] if len(value) > 4 else "***"
176
+ console.print(f"āœ… Set {key} = {masked_value}")
177
+ else:
178
+ console.print(f"āœ… Set {key} = {value}")
179
+
180
+
181
+ @config_group.command("get")
182
+ @click.argument("key")
183
+ def get_config(key):
184
+ """Get a configuration value."""
185
+
186
+ config = load_config()
187
+
188
+ if key not in config:
189
+ console.print(f"[yellow]Configuration key '{key}' not found.[/yellow]")
190
+ raise click.ClickException(f"Configuration key not found: {key}")
191
+
192
+ value = config[key]
193
+
194
+ if key == "api_key":
195
+ # Mask the API key for display
196
+ masked_value = "***" + value[-4:] if len(value) > 4 else "***"
197
+ console.print(masked_value)
198
+ else:
199
+ console.print(value)
200
+
201
+
202
+ @config_group.command("unset")
203
+ @click.argument("key")
204
+ def unset_config(key):
205
+ """Remove a configuration value."""
206
+
207
+ config = load_config()
208
+
209
+ if key not in config:
210
+ console.print(f"[yellow]Configuration key '{key}' not found.[/yellow]")
211
+ return
212
+
213
+ del config[key]
214
+ save_config(config)
215
+
216
+ console.print(f"āœ… Removed {key} from configuration")
217
+
218
+
219
+ @config_group.command("reset")
220
+ @click.option("--force", is_flag=True, help="Skip confirmation prompt")
221
+ def reset_config(force):
222
+ """Reset all configuration to defaults."""
223
+
224
+ if not force:
225
+ console.print("[yellow]This will remove all AIP configuration.[/yellow]")
226
+ confirm = input("Are you sure? (y/N): ").strip().lower()
227
+ if confirm not in ["y", "yes"]:
228
+ console.print("Cancelled.")
229
+ return
230
+
231
+ if CONFIG_FILE.exists():
232
+ CONFIG_FILE.unlink()
233
+ console.print(
234
+ "āœ… Configuration reset. Run 'aip config configure' to set up again."
235
+ )
236
+ else:
237
+ console.print("[yellow]No configuration found to reset.[/yellow]")
238
+
239
+
240
+ # Note: The config command group should be registered in main.py
241
+
242
+
243
+ @click.command()
244
+ def configure_command():
245
+ """Configure AIP CLI credentials and settings interactively."""
246
+
247
+ console.print(
248
+ Panel(
249
+ "[bold cyan]AIP Configuration[/bold cyan]\nConfigure your AIP CLI settings.",
250
+ title="šŸ”§ Configuration Setup",
251
+ border_style="cyan",
252
+ )
253
+ )
254
+
255
+ # Load existing config
256
+ config = load_config()
257
+
258
+ console.print("\n[bold]Enter your AIP configuration:[/bold]")
259
+ console.print("(Leave blank to keep current values)")
260
+ console.print("─" * 50)
261
+
262
+ # API URL
263
+ current_url = config.get("api_url", "")
264
+ console.print(
265
+ f"\n[cyan]AIP API URL[/cyan] {f'(current: {current_url})' if current_url else ''}:"
266
+ )
267
+ new_url = input("> ").strip()
268
+ if new_url:
269
+ config["api_url"] = new_url
270
+ elif not current_url:
271
+ config["api_url"] = "https://your-aip-instance.com"
272
+
273
+ # API Key
274
+ current_key_masked = (
275
+ "***" + config.get("api_key", "")[-4:] if config.get("api_key") else ""
276
+ )
277
+ console.print(
278
+ f"\n[cyan]AIP API Key[/cyan] {f'(current: {current_key_masked})' if current_key_masked else ''}:"
279
+ )
280
+ new_key = getpass.getpass("> ")
281
+ if new_key:
282
+ config["api_key"] = new_key
283
+
284
+ # Save configuration
285
+ save_config(config)
286
+
287
+ console.print(f"\nāœ… Configuration saved to: {CONFIG_FILE}")
288
+
289
+ # Test the new configuration
290
+ console.print("\nšŸ”Œ Testing connection...")
291
+ try:
292
+ from glaip_sdk import Client
293
+
294
+ # Create client with new config
295
+ client = Client(api_url=config["api_url"], api_key=config["api_key"])
296
+
297
+ # Try to list resources to test connection
298
+ try:
299
+ agents = client.list_agents()
300
+ console.print(f"āœ… Connection successful! Found {len(agents)} agents")
301
+ except Exception as e:
302
+ console.print(f"āš ļø Connection established but API call failed: {e}")
303
+ console.print(
304
+ " You may need to check your API permissions or network access"
305
+ )
306
+
307
+ client.close()
308
+
309
+ except Exception as e:
310
+ console.print(f"āŒ Connection failed: {e}")
311
+ console.print(" Please check your API URL and key")
312
+ console.print(" You can run 'aip status' later to test again")
313
+
314
+ console.print("\nšŸ’” You can now use AIP CLI commands!")
315
+ console.print(" • Run 'aip status' to check connection")
316
+ console.print(" • Run 'aip agents list' to see your agents")
@@ -0,0 +1,168 @@
1
+ """CLI initialization command.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ import getpass
8
+ import os
9
+ from pathlib import Path
10
+
11
+ import click
12
+ import yaml
13
+ from rich.console import Console
14
+ from rich.panel import Panel
15
+
16
+ console = Console()
17
+
18
+
19
+ @click.command()
20
+ @click.option("--no-scaffold", is_flag=True, help="Skip creating sample agent and tool")
21
+ @click.option("--no-demo", is_flag=True, help="Don't launch interactive demo")
22
+ def init_command(no_scaffold, no_demo):
23
+ """Initialize AIP project configuration."""
24
+
25
+ console.print(
26
+ Panel(
27
+ "[bold cyan]Welcome to AIP![/bold cyan]\nLet's set up your project.",
28
+ title="šŸš€ AIP Initialization",
29
+ border_style="cyan",
30
+ )
31
+ )
32
+
33
+ # Get configuration with better formatting
34
+ console.print("\n[bold]Step 1:[/bold] API Configuration")
35
+ console.print("─" * 50)
36
+
37
+ # Use built-in input for better control
38
+ console.print(
39
+ "\n[cyan]AIP API URL[/cyan] (default: https://your-aip-instance.com):"
40
+ )
41
+ api_url = input("> ").strip()
42
+ if not api_url:
43
+ api_url = "https://your-aip-instance.com"
44
+
45
+ console.print() # Add spacing
46
+ console.print("[cyan]AIP API Key[/cyan]:")
47
+ api_key = getpass.getpass("> ")
48
+
49
+ # Project configuration removed - not needed for AIP CLI
50
+
51
+ # Create config directory
52
+ config_dir = Path.home() / ".aip"
53
+ config_dir.mkdir(exist_ok=True)
54
+
55
+ # Save configuration
56
+ config = {"api_url": api_url, "api_key": api_key}
57
+
58
+ config_file = config_dir / "config.yaml"
59
+ with open(config_file, "w") as f:
60
+ yaml.dump(config, f, default_flow_style=False)
61
+
62
+ # Set secure file permissions (0600) - best effort on all platforms
63
+ try:
64
+ os.chmod(config_file, 0o600)
65
+ except Exception:
66
+ # Best effort - may fail on Windows or other non-POSIX systems
67
+ pass
68
+
69
+ console.print(f"\nāœ… Configuration saved to: {config_file}")
70
+
71
+ # Create sample agent and tool if requested
72
+ if not no_scaffold:
73
+ console.print("\n[bold]Step 2:[/bold] Sample Resources")
74
+ console.print("─" * 50)
75
+
76
+ console.print("\n[cyan]Create sample agent & tool?[/cyan] (Y/n):")
77
+ create_sample_resources = input("> ").strip().lower()
78
+ if create_sample_resources in ["", "y", "yes"]:
79
+ try:
80
+ from glaip_sdk import Client
81
+
82
+ # Set environment variables
83
+ os.environ["AIP_API_URL"] = api_url
84
+ os.environ["AIP_API_KEY"] = api_key
85
+
86
+ client = Client()
87
+
88
+ # Create sample agent
89
+ agent = client.create_agent(
90
+ name="hello-world",
91
+ instruction="You are a helpful AI assistant that says hello",
92
+ )
93
+ console.print(f"āœ… Created sample agent: {agent.name} (id: {agent.id})")
94
+
95
+ # Create sample tool
96
+ tool_content = '''def hello_tool(name="World"):
97
+ """A simple hello tool."""
98
+ return f"Hello, {name}!"
99
+ '''
100
+ with open("greeting_tool.py", "w") as f:
101
+ f.write(tool_content)
102
+
103
+ tool = client.create_tool("greeting_tool.py", framework="langchain")
104
+ console.print(f"āœ… Created sample tool: {tool.name} (id: {tool.id})")
105
+
106
+ except Exception as e:
107
+ console.print(f"āš ļø Warning: Could not create sample resources: {e}")
108
+
109
+ # Launch interactive demo if requested
110
+ if not no_demo:
111
+ console.print("\n[bold]Step 3:[/bold] Interactive Demo")
112
+ console.print("─" * 50)
113
+
114
+ console.print("\n[cyan]Start an interactive demo now?[/cyan] (Y/n):")
115
+ launch_demo = input("> ").strip().lower()
116
+ if launch_demo in ["", "y", "yes"]:
117
+ launch_interactive_demo()
118
+
119
+ console.print("\nšŸŽ‰ [bold green]AIP initialization complete![/bold green]")
120
+ console.print(f"šŸ“ Configuration: {config_file}")
121
+ console.print("šŸ’” Next steps:")
122
+ console.print(" • Run 'aip agents list' to see your agents")
123
+ console.print(" • Run 'aip tools list' to see your tools")
124
+ console.print(" • Run 'aip status' to check connection")
125
+
126
+
127
+ def launch_interactive_demo():
128
+ """Launch interactive demo with sample agent."""
129
+ try:
130
+ from glaip_sdk import Client
131
+
132
+ console.print(
133
+ Panel(
134
+ "[bold green]Interactive Demo[/bold green]\nType to talk to hello-world. Ctrl+C to exit.",
135
+ title="šŸŽ® Demo Mode",
136
+ border_style="green",
137
+ )
138
+ )
139
+
140
+ client = Client()
141
+ agents = client.find_agents(name="hello-world")
142
+ if not agents:
143
+ console.print("āŒ Sample agent not found")
144
+ return
145
+
146
+ agent = agents[0] # Use the first (and should be only) agent
147
+
148
+ while True:
149
+ try:
150
+ console.print("\n> ", end="")
151
+ user_input = input().strip()
152
+ if user_input.lower() in ["exit", "quit", "bye"]:
153
+ break
154
+
155
+ response = agent.run(user_input)
156
+ console.print(f"šŸ¤– {response}")
157
+
158
+ except KeyboardInterrupt:
159
+ break
160
+ except Exception as e:
161
+ console.print(f"āŒ Error: {e}")
162
+
163
+ except Exception as e:
164
+ console.print(f"āš ļø Could not launch demo: {e}")
165
+
166
+
167
+ # Note: The init command should be registered in main.py, not here
168
+ # This prevents circular imports