agentic-fabriq-sdk 0.1.6__py3-none-any.whl → 0.1.8__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.

Potentially problematic release.


This version of agentic-fabriq-sdk might be problematic. Click here for more details.

af_cli/commands/auth.py CHANGED
@@ -98,9 +98,12 @@ def login(
98
98
  # Extract and save token data
99
99
  token_data = token_storage.extract_token_info(tokens)
100
100
 
101
- # Override tenant_id if provided
101
+ # Override tenant_id if provided, otherwise use default for Keycloak JWTs
102
102
  if tenant_id:
103
103
  token_data.tenant_id = tenant_id
104
+ elif not token_data.tenant_id:
105
+ # Keycloak JWTs don't have tenant_id, use the same default as the backend
106
+ token_data.tenant_id = "550e8400-e29b-41d4-a716-446655440000"
104
107
 
105
108
  # Save tokens
106
109
  token_storage.save(token_data)
@@ -109,8 +112,7 @@ def login(
109
112
  config.access_token = token_data.access_token
110
113
  config.refresh_token = token_data.refresh_token
111
114
  config.token_expires_at = token_data.expires_at
112
- if token_data.tenant_id:
113
- config.tenant_id = token_data.tenant_id
115
+ config.tenant_id = token_data.tenant_id # Always set tenant_id
114
116
  config.save()
115
117
 
116
118
  # Display success message
@@ -190,7 +192,7 @@ def status():
190
192
 
191
193
  if not token_data:
192
194
  warning("Not authenticated")
193
- info("Run 'af auth login' to authenticate")
195
+ info("Run 'afctl auth login' to authenticate")
194
196
  return
195
197
 
196
198
  # Create status table
@@ -242,9 +244,9 @@ def status():
242
244
  # Show recommendations
243
245
  if is_expired:
244
246
  if token_data.refresh_token:
245
- info("Token has expired. Run 'af auth refresh' to get a new token")
247
+ info("Token has expired. Run 'afctl auth refresh' to get a new token")
246
248
  else:
247
- info("Token has expired. Run 'af auth login' to re-authenticate")
249
+ info("Token has expired. Run 'afctl auth login' to re-authenticate")
248
250
 
249
251
 
250
252
  @app.command()
@@ -270,7 +272,7 @@ def refresh(
270
272
 
271
273
  if not token_data or not token_data.refresh_token:
272
274
  error("No refresh token available")
273
- info("Run 'af auth login' to authenticate")
275
+ info("Run 'afctl auth login' to authenticate")
274
276
  raise typer.Exit(1)
275
277
 
276
278
  try:
@@ -304,7 +306,7 @@ def refresh(
304
306
 
305
307
  except Exception as e:
306
308
  error(f"Token refresh failed: {e}")
307
- error("Please run 'af auth login' to re-authenticate")
309
+ error("Please run 'afctl auth login' to re-authenticate")
308
310
 
309
311
  # Clear invalid tokens
310
312
  token_storage.delete()
@@ -366,7 +368,7 @@ def whoami():
366
368
 
367
369
  if not token_data:
368
370
  warning("Not authenticated")
369
- info("Run 'af auth login' to authenticate")
371
+ info("Run 'afctl auth login' to authenticate")
370
372
  return
371
373
 
372
374
  # Create user info table
af_cli/commands/config.py CHANGED
@@ -93,7 +93,7 @@ def reset():
93
93
  config.clear_auth()
94
94
 
95
95
  # Reset to defaults
96
- config.gateway_url = "http://localhost:8000"
96
+ config.gateway_url = "https://dashboard.agenticfabriq.com"
97
97
  config.tenant_id = None
98
98
  config.output_format = "table"
99
99
 
af_cli/commands/tools.py CHANGED
@@ -6,7 +6,7 @@ Tool management commands for the Agentic Fabric CLI.
6
6
  import typer
7
7
 
8
8
  from af_cli.core.client import get_client
9
- from af_cli.core.output import error, info, print_output, success, warning
9
+ from af_cli.core.output import debug, error, info, print_output, success, warning
10
10
 
11
11
  app = typer.Typer(help="Tool management commands")
12
12
 
@@ -15,45 +15,107 @@ app = typer.Typer(help="Tool management commands")
15
15
  def list(
16
16
  format: str = typer.Option("table", "--format", "-f", help="Output format"),
17
17
  ):
18
- """List tools."""
18
+ """List your tool connections (configured and connected tools)."""
19
19
  try:
20
20
  with get_client() as client:
21
- response = client.get("/api/v1/tools")
22
- tools = response["tools"]
21
+ connections = client.get("/api/v1/user-connections")
23
22
 
24
- if not tools:
25
- warning("No tools found")
23
+ if not connections:
24
+ warning("No tool connections found. Add connections in the dashboard UI.")
26
25
  return
27
26
 
27
+ # Format for better display
28
+ display_data = []
29
+ for conn in connections:
30
+ # Format tool name nicely (e.g., "google_docs" -> "Google Docs")
31
+ tool_name = conn.get("tool", "N/A").replace("_", " ").title()
32
+
33
+ # Status indicator
34
+ status = "✓ Connected" if conn.get("connected") else "○ Configured"
35
+
36
+ display_data.append({
37
+ "Tool": tool_name,
38
+ "ID": conn.get("connection_id", "N/A"),
39
+ "Name": conn.get("display_name") or conn.get("connection_id", "N/A"),
40
+ "Status": status,
41
+ "Method": conn.get("method", "oauth"),
42
+ "Added": conn.get("created_at", "N/A")[:10] if conn.get("created_at") else "N/A",
43
+ })
44
+
28
45
  print_output(
29
- tools,
46
+ display_data,
30
47
  format_type=format,
31
- title="Tools"
48
+ title="Your Tool Connections"
32
49
  )
33
50
 
34
51
  except Exception as e:
35
- error(f"Failed to list tools: {e}")
52
+ error(f"Failed to list tool connections: {e}")
36
53
  raise typer.Exit(1)
37
54
 
38
55
 
39
56
  @app.command()
40
57
  def get(
41
- tool_id: str = typer.Argument(..., help="Tool ID"),
58
+ connection_id: str = typer.Argument(..., help="Connection ID (e.g., 'google', 'slack')"),
42
59
  format: str = typer.Option("table", "--format", "-f", help="Output format"),
43
60
  ):
44
- """Get tool details."""
61
+ """Get tool connection details."""
45
62
  try:
46
63
  with get_client() as client:
47
- tool = client.get(f"/api/v1/tools/{tool_id}")
64
+ # Get all user connections and find the matching one
65
+ connections = client.get("/api/v1/user-connections")
66
+
67
+ # Find the specific connection
68
+ connection = None
69
+ for conn in connections:
70
+ if conn.get("connection_id") == connection_id or conn.get("tool") == connection_id:
71
+ connection = conn
72
+ break
73
+
74
+ if not connection:
75
+ error(f"Connection '{connection_id}' not found")
76
+ info("Available connections:")
77
+ for conn in connections:
78
+ info(f" - {conn.get('tool')} (ID: {conn.get('connection_id')})")
79
+ raise typer.Exit(1)
80
+
81
+ # Format tool name nicely
82
+ tool_name = connection.get("tool", "N/A").replace("_", " ").title()
83
+
84
+ # Format the connection details for display
85
+ details = {
86
+ "Tool": tool_name,
87
+ "Connection ID": connection.get("connection_id", "N/A"),
88
+ "Display Name": connection.get("display_name") or connection.get("connection_id", "N/A"),
89
+ "Status": "✓ Connected" if connection.get("connected") else "○ Configured",
90
+ "Method": connection.get("method", "oauth"),
91
+ "Created": connection.get("created_at", "N/A"),
92
+ "Updated": connection.get("updated_at", "N/A"),
93
+ }
94
+
95
+ # Add tool-specific fields if present
96
+ if connection.get("team_name"):
97
+ details["Team Name"] = connection.get("team_name")
98
+ if connection.get("team_id"):
99
+ details["Team ID"] = connection.get("team_id")
100
+ if connection.get("bot_user_id"):
101
+ details["Bot User ID"] = connection.get("bot_user_id")
102
+ if connection.get("email"):
103
+ details["Email"] = connection.get("email")
104
+ if connection.get("login"):
105
+ details["GitHub Login"] = connection.get("login")
106
+ if connection.get("workspace_name"):
107
+ details["Workspace Name"] = connection.get("workspace_name")
108
+ if connection.get("scopes"):
109
+ details["Scopes"] = ", ".join(connection.get("scopes", []))
48
110
 
49
111
  print_output(
50
- tool,
112
+ details,
51
113
  format_type=format,
52
- title=f"Tool {tool_id}"
114
+ title=f"{tool_name} Connection Details"
53
115
  )
54
116
 
55
117
  except Exception as e:
56
- error(f"Failed to get tool: {e}")
118
+ error(f"Failed to get tool connection: {e}")
57
119
  raise typer.Exit(1)
58
120
 
59
121
 
@@ -80,4 +142,364 @@ def invoke(
80
142
 
81
143
  except Exception as e:
82
144
  error(f"Failed to invoke tool: {e}")
145
+ raise typer.Exit(1)
146
+
147
+
148
+ @app.command()
149
+ def add(
150
+ tool: str = typer.Argument(..., help="Tool name (google_drive, google_slides, slack, notion, github, etc.)"),
151
+ connection_id: str = typer.Option(..., "--connection-id", help="Unique connection ID"),
152
+ display_name: str = typer.Option(None, "--display-name", help="Human-readable name"),
153
+ method: str = typer.Option(..., "--method", help="Connection method: 'api', 'credentials', or 'oauth'"),
154
+
155
+ # API method fields
156
+ token: str = typer.Option(None, "--token", help="API token (for api method)"),
157
+
158
+ # Credentials method fields
159
+ client_id: str = typer.Option(None, "--client-id", help="OAuth client ID (for credentials method)"),
160
+ client_secret: str = typer.Option(None, "--client-secret", help="OAuth client secret (for credentials method)"),
161
+ redirect_uri: str = typer.Option(None, "--redirect-uri", help="OAuth redirect URI (optional, auto-generated)"),
162
+ ):
163
+ """
164
+ Add a new tool connection with credentials.
165
+
166
+ Examples:
167
+ # Notion (api method - single token)
168
+ afctl tools add notion --connection-id notion-work --method api --token "secret_abc123"
169
+
170
+ # Google (credentials method - OAuth app)
171
+ afctl tools add google --connection-id google-work --method credentials \\
172
+ --client-id "123.apps.googleusercontent.com" \\
173
+ --client-secret "GOCSPX-abc123"
174
+
175
+ # Slack bot (api method)
176
+ afctl tools add slack --connection-id slack-bot --method api --token "xoxb-123..."
177
+ """
178
+ try:
179
+ from af_cli.core.config import get_config
180
+
181
+ with get_client() as client:
182
+ # Validate tool name - check for common mistakes
183
+ if tool.lower() == "google":
184
+ error("❌ Invalid tool name: 'google'")
185
+ info("")
186
+ info("Please specify the exact Google Workspace tool:")
187
+ info(" • google_drive - Google Drive")
188
+ info(" • google_docs - Google Docs")
189
+ info(" • google_sheets - Google Sheets")
190
+ info(" • google_slides - Google Slides")
191
+ info(" • gmail - Gmail")
192
+ info(" • google_calendar - Google Calendar")
193
+ info(" • google_meet - Google Meet")
194
+ info(" • google_forms - Google Forms")
195
+ info(" • google_classroom - Google Classroom")
196
+ info(" • google_people - Google People (Contacts)")
197
+ info(" • google_chat - Google Chat")
198
+ info(" • google_tasks - Google Tasks")
199
+ info("")
200
+ info("Example:")
201
+ info(f" afctl tools add google_drive --connection-id {connection_id} --method {method}")
202
+ raise typer.Exit(1)
203
+
204
+ # Validate method
205
+ if method not in ["api", "credentials", "oauth"]:
206
+ error("Method must be 'api', 'credentials', or 'oauth'")
207
+ raise typer.Exit(1)
208
+
209
+ # Validate API method requirements
210
+ if method == "api":
211
+ if not token:
212
+ error("API method requires --token")
213
+ info(f"Example: afctl tools add {tool} --connection-id {connection_id} --method api --token YOUR_TOKEN")
214
+ raise typer.Exit(1)
215
+
216
+ # Validate credentials method requirements
217
+ elif method == "credentials":
218
+ if not client_id or not client_secret:
219
+ error("Credentials method requires --client-id and --client-secret")
220
+ info(f"Example: afctl tools add {tool} --connection-id {connection_id} --method credentials \\")
221
+ info(f" --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET")
222
+ raise typer.Exit(1)
223
+
224
+ info(f"Creating connection: {connection_id}")
225
+ info(f"Tool: {tool}")
226
+ info(f"Method: {method}")
227
+
228
+ # Step 1: Create connection metadata
229
+ connection_data = {
230
+ "tool": tool,
231
+ "connection_id": connection_id,
232
+ "display_name": display_name or connection_id,
233
+ "method": method,
234
+ }
235
+
236
+ client.post("/api/v1/user-connections", data=connection_data)
237
+ success(f"✅ Connection entry created: {connection_id}")
238
+
239
+ # Step 2: Store credentials based on method
240
+ if method == "credentials" or method == "oauth":
241
+ # Determine the API base tool name (Google tools all use "google")
242
+ api_tool_name = "google" if (tool.startswith("google_") or tool == "gmail") else tool
243
+
244
+ # Auto-generate redirect_uri if not provided
245
+ if not redirect_uri:
246
+ config = get_config()
247
+ redirect_uri = f"{config.gateway_url}/api/v1/tools/{api_tool_name}/oauth/callback"
248
+ info(f"Using default redirect URI: {redirect_uri}")
249
+
250
+ # Store OAuth app config
251
+ info("Storing OAuth app credentials...")
252
+ config_payload = {
253
+ "client_id": client_id,
254
+ "client_secret": client_secret,
255
+ }
256
+ if redirect_uri:
257
+ config_payload["redirect_uri"] = redirect_uri
258
+
259
+ client.post(
260
+ f"/api/v1/tools/{api_tool_name}/config?connection_id={connection_id}",
261
+ data=config_payload
262
+ )
263
+ success("✅ OAuth app credentials stored")
264
+ info("")
265
+ info(f"Next: Run 'afctl tools connect {connection_id}' to complete OAuth setup")
266
+
267
+ elif method == "api":
268
+ # Store API token directly
269
+ info("Storing API credentials...")
270
+
271
+ # Tool-specific endpoint and payload mappings
272
+ if tool == "notion":
273
+ # Notion uses /config endpoint with integration_token field
274
+ endpoint = f"/api/v1/tools/{tool}/config?connection_id={connection_id}"
275
+ cred_payload = {"integration_token": token}
276
+ else:
277
+ # Generic tools use /connection endpoint with api_token field
278
+ endpoint = f"/api/v1/tools/{tool}/connection?connection_id={connection_id}"
279
+ cred_payload = {"api_token": token}
280
+
281
+ client.post(endpoint, data=cred_payload)
282
+ success("✅ API credentials stored")
283
+ success(f"✅ Connection '{connection_id}' is ready to use!")
284
+
285
+ # Show helpful info
286
+ info("")
287
+ info("View your connections:")
288
+ info(f" • List all: afctl tools list")
289
+ info(f" • View details: afctl tools get {connection_id}")
290
+
291
+ except Exception as e:
292
+ error(f"Failed to add connection: {e}")
293
+ raise typer.Exit(1)
294
+
295
+
296
+ @app.command()
297
+ def connect(
298
+ connection_id: str = typer.Argument(..., help="Connection ID to connect"),
299
+ ):
300
+ """Complete OAuth connection (open browser for authorization)."""
301
+ try:
302
+ import webbrowser
303
+ import time
304
+
305
+ with get_client() as client:
306
+ # Get connection info
307
+ connections = client.get("/api/v1/user-connections")
308
+
309
+ connection = None
310
+ for conn in connections:
311
+ if conn.get("connection_id") == connection_id:
312
+ connection = conn
313
+ break
314
+
315
+ if not connection:
316
+ error(f"Connection '{connection_id}' not found")
317
+ info("Run 'afctl tools list' to see available connections")
318
+ raise typer.Exit(1)
319
+
320
+ tool = connection["tool"]
321
+ method = connection["method"]
322
+
323
+ # Only credentials/oauth method needs OAuth completion
324
+ if method not in ["credentials", "oauth"]:
325
+ error(f"Connection '{connection_id}' uses '{method}' method")
326
+ info("Only 'credentials' or 'oauth' method connections need OAuth setup")
327
+ info("API connections are already connected after 'afctl tools add'")
328
+ raise typer.Exit(1)
329
+
330
+ # Check if already connected
331
+ if connection.get("connected"):
332
+ warning(f"Connection '{connection_id}' is already connected")
333
+ confirm = typer.confirm("Do you want to reconnect (re-authorize)?")
334
+ if not confirm:
335
+ return
336
+
337
+ # Determine the API base tool name (Google tools all use "google")
338
+ api_tool_name = "google" if (tool.startswith("google_") or tool == "gmail") else tool
339
+
340
+ # Initiate OAuth flow
341
+ info(f"Initiating OAuth for {tool}...")
342
+
343
+ # For Google tools, pass the specific tool_type parameter
344
+ tool_type_param = f"&tool_type={tool}" if tool != api_tool_name else ""
345
+
346
+ result = client.post(
347
+ f"/api/v1/tools/{api_tool_name}/connect/initiate?connection_id={connection_id}{tool_type_param}",
348
+ data={}
349
+ )
350
+
351
+ debug(f"Backend response: {result}")
352
+
353
+ # Different tools use different field names for the auth URL
354
+ auth_url = (
355
+ result.get("authorization_url") or
356
+ result.get("auth_url") or
357
+ result.get("oauth_url")
358
+ )
359
+
360
+ if not auth_url:
361
+ error("Failed to get authorization URL from backend")
362
+ error(f"Response keys: {list(result.keys())}")
363
+ debug(f"Full response: {result}")
364
+ raise typer.Exit(1)
365
+
366
+ info("Opening browser for authentication...")
367
+ info("")
368
+ info(f"If browser doesn't open, visit: {auth_url}")
369
+
370
+ # Open browser
371
+ webbrowser.open(auth_url)
372
+
373
+ info("")
374
+ info("Waiting for authorization...")
375
+ info("(Complete the login in your browser)")
376
+
377
+ # Poll for connection completion
378
+ max_attempts = 120 # 2 minutes
379
+ for attempt in range(max_attempts):
380
+ time.sleep(1)
381
+
382
+ # Check connection status
383
+ connections = client.get("/api/v1/user-connections")
384
+ for conn in connections:
385
+ if conn.get("connection_id") == connection_id:
386
+ if conn.get("connected"):
387
+ info("")
388
+ success(f"✅ Successfully connected to {tool}!")
389
+
390
+ # Show connection details
391
+ info(f"Connection ID: {connection_id}")
392
+ if conn.get("email"):
393
+ info(f"Email: {conn['email']}")
394
+ if conn.get("team_name"):
395
+ info(f"Team: {conn['team_name']}")
396
+ if conn.get("login"):
397
+ info(f"GitHub: {conn['login']}")
398
+
399
+ return
400
+ break
401
+
402
+ # Timeout
403
+ error("")
404
+ error("Timeout: Authorization not completed within 2 minutes")
405
+ info("Please try again or check your browser")
406
+ raise typer.Exit(1)
407
+
408
+ except Exception as e:
409
+ error(f"Failed to connect: {e}")
410
+ raise typer.Exit(1)
411
+
412
+
413
+ @app.command()
414
+ def disconnect(
415
+ connection_id: str = typer.Argument(..., help="Connection ID to disconnect"),
416
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
417
+ ):
418
+ """Disconnect a tool (remove credentials but keep connection entry)."""
419
+ try:
420
+ with get_client() as client:
421
+ # Get connection info
422
+ connections = client.get("/api/v1/user-connections")
423
+
424
+ connection = None
425
+ for conn in connections:
426
+ if conn.get("connection_id") == connection_id:
427
+ connection = conn
428
+ break
429
+
430
+ if not connection:
431
+ error(f"Connection '{connection_id}' not found")
432
+ raise typer.Exit(1)
433
+
434
+ tool = connection["tool"]
435
+ tool_display = connection.get("display_name") or connection_id
436
+
437
+ # Check if connected
438
+ if not connection.get("connected"):
439
+ error(f"Connection '{connection_id}' is already disconnected")
440
+ info(f"Use 'afctl tools get {connection_id}' to view status")
441
+ raise typer.Exit(1)
442
+
443
+ # Confirm
444
+ if not force:
445
+ warning(f"This will remove OAuth tokens/credentials for '{tool_display}'")
446
+ info("You can reconnect later with 'afctl tools connect'")
447
+ confirm = typer.confirm(f"Disconnect {tool} connection '{connection_id}'?")
448
+ if not confirm:
449
+ info("Cancelled")
450
+ return
451
+
452
+ # Delete connection credentials
453
+ client.delete(
454
+ f"/api/v1/tools/{tool}/connection?connection_id={connection_id}"
455
+ )
456
+
457
+ success(f"✅ Disconnected: {connection_id}")
458
+ info("Connection entry preserved.")
459
+ info(f"Run 'afctl tools connect {connection_id}' to reconnect.")
460
+
461
+ except Exception as e:
462
+ error(f"Failed to disconnect: {e}")
463
+ raise typer.Exit(1)
464
+
465
+
466
+ @app.command()
467
+ def remove(
468
+ connection_id: str = typer.Argument(..., help="Connection ID to remove"),
469
+ force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
470
+ ):
471
+ """Remove a tool connection completely (delete entry and credentials)."""
472
+ try:
473
+ with get_client() as client:
474
+ # Get connection info
475
+ connections = client.get("/api/v1/user-connections")
476
+
477
+ connection = None
478
+ for conn in connections:
479
+ if conn.get("connection_id") == connection_id:
480
+ connection = conn
481
+ break
482
+
483
+ if not connection:
484
+ error(f"Connection '{connection_id}' not found")
485
+ raise typer.Exit(1)
486
+
487
+ tool = connection["tool"]
488
+ tool_display = connection.get("display_name") or connection_id
489
+
490
+ # Confirm
491
+ if not force:
492
+ warning("⚠️ This will permanently delete the connection and credentials")
493
+ confirm = typer.confirm(f"Remove {tool} connection '{tool_display}'?")
494
+ if not confirm:
495
+ info("Cancelled")
496
+ return
497
+
498
+ # Delete connection entry (backend will cascade delete credentials)
499
+ client.delete(f"/api/v1/user-connections/{connection_id}")
500
+
501
+ success(f"✅ Removed: {connection_id}")
502
+
503
+ except Exception as e:
504
+ error(f"Failed to remove: {e}")
83
505
  raise typer.Exit(1)
af_cli/core/client.py CHANGED
@@ -33,7 +33,7 @@ class AFClient:
33
33
  debug(f"Response: {response.status_code} {response.url}")
34
34
 
35
35
  if response.status_code == 401:
36
- error("Authentication failed. Please run 'af auth login'")
36
+ error("Authentication failed. Please run 'afctl auth login'")
37
37
  raise typer.Exit(1)
38
38
 
39
39
  if response.status_code == 403:
@@ -43,12 +43,16 @@ class AFClient:
43
43
  if response.status_code >= 400:
44
44
  try:
45
45
  error_data = response.json()
46
- error_message = error_data.get("message", "Unknown error")
46
+ # Try different error message fields (FastAPI uses "detail")
47
+ error_message = error_data.get("detail") or error_data.get("message") or "Unknown error"
47
48
  error(f"API Error: {error_message}")
48
- if self.config.verbose and "details" in error_data:
49
- debug(f"Error details: {json.dumps(error_data['details'], indent=2)}")
49
+ # Always show full response for debugging
50
+ debug(f"Response status: {response.status_code}")
51
+ debug(f"Request URL: {response.url}")
52
+ debug(f"Full response: {json.dumps(error_data, indent=2)}")
50
53
  except:
51
- error(f"HTTP Error: {response.status_code} {response.text}")
54
+ error(f"HTTP Error: {response.status_code}")
55
+ debug(f"Response text: {response.text}")
52
56
  raise typer.Exit(1)
53
57
 
54
58
  try:
af_cli/core/output.py CHANGED
@@ -55,12 +55,12 @@ def print_table(
55
55
  if columns is None:
56
56
  columns = list(data[0].keys())
57
57
 
58
- # Create table
59
- table = Table(title=title)
58
+ # Create table with expand to fill terminal width and show grid lines
59
+ table = Table(title=title, expand=True, show_lines=True)
60
60
 
61
- # Add columns
61
+ # Add columns with no_wrap to prevent text wrapping
62
62
  for column in columns:
63
- table.add_column(column.replace("_", " ").title(), style="cyan")
63
+ table.add_column(column.replace("_", " ").title(), style="cyan", no_wrap=True)
64
64
 
65
65
  # Add rows
66
66
  for row in data:
af_cli/main.py CHANGED
@@ -68,7 +68,7 @@ def status():
68
68
  if config.access_token:
69
69
  table.add_row("Authentication", "✅ Authenticated", f"Tenant: {config.tenant_id}")
70
70
  else:
71
- table.add_row("Authentication", "❌ Not authenticated", "Run 'af auth login'")
71
+ table.add_row("Authentication", "❌ Not authenticated", "Run 'afctl auth login'")
72
72
 
73
73
  # Check configuration
74
74
  config_path = config.config_file
@@ -83,7 +83,7 @@ def status():
83
83
  @app.command()
84
84
  def init(
85
85
  gateway_url: str = typer.Option(
86
- "http://localhost:8000",
86
+ "https://dashboard.agenticfabriq.com",
87
87
  "--gateway-url",
88
88
  "-g",
89
89
  help="Gateway URL"
@@ -125,7 +125,7 @@ def init(
125
125
  if tenant_id:
126
126
  info(f"Tenant ID: {tenant_id}")
127
127
  else:
128
- info("Run 'af auth login' to authenticate")
128
+ info("Run 'afctl auth login' to authenticate")
129
129
 
130
130
 
131
131
  @app.callback()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-fabriq-sdk
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Agentic Fabriq SDK: high-level client, CLI tool, DX helpers, and auth for AI agents
5
5
  License: Apache-2.0
6
6
  Keywords: fabriq,agentic-fabriq,sdk,ai,agents,agentic,fabric,cli
@@ -90,8 +90,8 @@ DX orchestration:
90
90
  ```python
91
91
  from af_sdk.dx import ToolFabric, AgentFabric, Agent, tool
92
92
 
93
- slack = ToolFabric(provider="slack", base_url="http://localhost:8000", access_token=TOKEN, tenant_id=TENANT)
94
- agents = AgentFabric(base_url="http://localhost:8000", access_token=TOKEN, tenant_id=TENANT)
93
+ slack = ToolFabric(provider="slack", base_url="https://dashboard.agenticfabriq.com", access_token=TOKEN, tenant_id=TENANT)
94
+ agents = AgentFabric(base_url="https://dashboard.agenticfabriq.com", access_token=TOKEN, tenant_id=TENANT)
95
95
 
96
96
  @tool
97
97
  def echo(x: str) -> str:
@@ -101,7 +101,7 @@ bot = Agent(
101
101
  system_prompt="demo",
102
102
  tools=[echo],
103
103
  agents=agents.get_agents(["summarizer"]),
104
- base_url="http://localhost:8000",
104
+ base_url="https://dashboard.agenticfabriq.com",
105
105
  access_token=TOKEN,
106
106
  tenant_id=TENANT,
107
107
  provider_fabrics={"slack": slack},
@@ -1,18 +1,18 @@
1
1
  af_cli/__init__.py,sha256=F2T4x4H3VIdmTjHRyV5DkaRvbZcdHYzAWD2hxtTplE4,188
2
2
  af_cli/commands/__init__.py,sha256=Qngm2Yks6oTKazlxCZA_tIAHXwHoU6Oc7Pw5BGkA7W4,49
3
3
  af_cli/commands/agents.py,sha256=EBAZgY5YbcR6npN0m7n1YB3WUTnW050Dd6FfORn0TtQ,8433
4
- af_cli/commands/auth.py,sha256=nPJYHJiAi1G_trbgZsDao_omhRZk777J0eceVxapuBg,11826
5
- af_cli/commands/config.py,sha256=IbIlwDHeVGsa0nY6XxZw_7nqh_jUKUH3M7oe92zcrAk,2545
4
+ af_cli/commands/auth.py,sha256=EuVIuTzpQ6eC6Tq9rdBF83HpfN-Jb4O0Ep_CLwhorUo,12071
5
+ af_cli/commands/config.py,sha256=vKTYc9noPNQQe4rhS2V9def1kzDtjB14ptWKJpdxUlQ,2559
6
6
  af_cli/commands/mcp_servers.py,sha256=kr2MskqtwdA1434_9oEyEydlZ5Ycq8a1Vt5wSC0AqRE,2420
7
7
  af_cli/commands/secrets.py,sha256=_XvtST9G7US_0MqHywSqRdp2FXUr76OTiD-SH4WXoJU,3472
8
- af_cli/commands/tools.py,sha256=GVNJgs4E2l9gQp4oPOcJh4IQxx0HdX-xe0wk4DitZm0,2273
8
+ af_cli/commands/tools.py,sha256=9wPXpemZh9YDCVKdIgvGFzlxMwSy0BuNg50Fs1DU6y0,21188
9
9
  af_cli/core/__init__.py,sha256=cQ0H7rGfaMISQPhoNe4Xfu_EKU2TqRVt2OMI7tPea5U,51
10
- af_cli/core/client.py,sha256=B5Q4bTMAzSdG3Xh46scH9pj89MGvDvjVQCq4IYTDPnU,3693
10
+ af_cli/core/client.py,sha256=BELf6889BOzOWP6kCk4hSY4DolIATB0YNpui38l7EaI,3939
11
11
  af_cli/core/config.py,sha256=zTrbZTtBZqG5Ktsbomr1w4u9uKdyc1nUieXIZLYsvIk,7355
12
12
  af_cli/core/oauth.py,sha256=sCzo97TZyx8sLmo0GYv53P3zoABK6htRCivHhRpPRdI,18162
13
- af_cli/core/output.py,sha256=s0lSvQbqpam1QHIdtUjZPfJ2GVSH5aYjKq60QY7DO3M,4674
13
+ af_cli/core/output.py,sha256=tL5z7M-tLu2M1Yl8O4M7OPP7iQivC1b_YUUB468Od5Y,4811
14
14
  af_cli/core/token_storage.py,sha256=WhOQLx5_9pn2lAlFX01Y5DmWO7B9BJYfEkASCsBQwaI,7738
15
- af_cli/main.py,sha256=shhGqDUSY1pBXA5QIxBj04Y9pMYdd7mCGBqsjBq49p4,5148
15
+ af_cli/main.py,sha256=EdZk87HkL8jJwqn5flrbz3ecMIBy6XbrUxvvMAC7Koc,5168
16
16
  af_sdk/__init__.py,sha256=gZ7nGfDRMJzPiIFrfcKytYt0cyVVPorOQaWq5X3fL0M,1262
17
17
  af_sdk/auth/__init__.py,sha256=WUtbNo1KS6Jm-2ssCo21mwBmMKRxT2HtjnfXZeIKSQg,703
18
18
  af_sdk/auth/dpop.py,sha256=s0uiyxxuzsVQNtSexji1htJoxrALwlf1P9507xa-M3Y,1285
@@ -34,7 +34,7 @@ af_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  af_sdk/transport/__init__.py,sha256=HsOc6MmlxIS-PSYC_-6E36-dZYyT_auZeoXvGzVAqeg,104
35
35
  af_sdk/transport/http.py,sha256=QB3eqQbwug95QHf5PG_714NKtlTjV9PzVTo8izJCylc,13203
36
36
  af_sdk/vault.py,sha256=QVNGigIw8ND5sVXt05gvUY222b5-i9EbzLWNsDGdOU4,17926
37
- agentic_fabriq_sdk-0.1.6.dist-info/METADATA,sha256=nI_bwhX6XBBMx7idHBEePLu6RzFJhDs-5zeWknDSZsk,3122
38
- agentic_fabriq_sdk-0.1.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
39
- agentic_fabriq_sdk-0.1.6.dist-info/entry_points.txt,sha256=XUO2EaJhUtUS5pwVIkhemC-nEeFbKgXXLW97gQCCGm8,41
40
- agentic_fabriq_sdk-0.1.6.dist-info/RECORD,,
37
+ agentic_fabriq_sdk-0.1.8.dist-info/METADATA,sha256=QenHN2T37YomL0BrwUdLZGEcpHNkl_-AFmTXy3lDmWw,3164
38
+ agentic_fabriq_sdk-0.1.8.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
39
+ agentic_fabriq_sdk-0.1.8.dist-info/entry_points.txt,sha256=XUO2EaJhUtUS5pwVIkhemC-nEeFbKgXXLW97gQCCGm8,41
40
+ agentic_fabriq_sdk-0.1.8.dist-info/RECORD,,