ainative-python 2.0.0__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,184 @@
1
+ """
2
+ Swarm Management CLI Commands
3
+
4
+ Commands for managing agent swarms (list, create, delete, scale, analytics).
5
+ """
6
+
7
+ import click
8
+ import json
9
+ from typing import Optional
10
+ from rich.console import Console
11
+ from rich.table import Table
12
+ from rich.panel import Panel
13
+
14
+ from ..client import AINativeClient
15
+
16
+
17
+ console = Console()
18
+
19
+
20
+ def get_client() -> AINativeClient:
21
+ """Get authenticated client."""
22
+ import os
23
+ from ..auth import AuthConfig
24
+
25
+ api_key = os.getenv("AINATIVE_API_KEY")
26
+ if not api_key:
27
+ raise click.ClickException("AINATIVE_API_KEY environment variable not set")
28
+
29
+ return AINativeClient(
30
+ auth_config=AuthConfig(api_key=api_key),
31
+ base_url=os.getenv("AINATIVE_BASE_URL"),
32
+ organization_id=os.getenv("AINATIVE_ORG_ID")
33
+ )
34
+
35
+
36
+ @click.group(name="swarm")
37
+ def swarm_group():
38
+ """Manage agent swarms."""
39
+ pass
40
+
41
+
42
+ @swarm_group.command(name="list")
43
+ @click.option("--project-id", help="Filter by project ID")
44
+ @click.option("--status", help="Filter by status")
45
+ @click.option("--format", type=click.Choice(["table", "json"]), default="table",
46
+ help="Output format")
47
+ def list_swarms(project_id: Optional[str], status: Optional[str], format: str):
48
+ """List all swarms."""
49
+ try:
50
+ client = get_client()
51
+ result = client.agent_swarm.list_swarms(
52
+ project_id=project_id,
53
+ status=status
54
+ )
55
+
56
+ swarms = result.get("swarms", [])
57
+
58
+ if format == "json":
59
+ click.echo(json.dumps(swarms, indent=2))
60
+ else:
61
+ table = Table(title="Agent Swarms")
62
+ table.add_column("ID", style="cyan")
63
+ table.add_column("Name", style="bold")
64
+ table.add_column("Status", style="green")
65
+ table.add_column("Agents", justify="right")
66
+ table.add_column("Project", style="dim")
67
+
68
+ for swarm in swarms:
69
+ table.add_row(
70
+ swarm.get("id", ""),
71
+ swarm.get("name", ""),
72
+ swarm.get("status", ""),
73
+ str(swarm.get("agent_count", 0)),
74
+ swarm.get("project_id", "")
75
+ )
76
+
77
+ console.print(table)
78
+ console.print(f"\nTotal: {len(swarms)} swarms")
79
+
80
+ except Exception as e:
81
+ click.echo(f"Error: {str(e)}", err=True)
82
+
83
+
84
+ @swarm_group.command(name="create")
85
+ @click.argument("name")
86
+ @click.option("--project-id", required=True, help="Project ID")
87
+ @click.option("--objective", required=True, help="Swarm objective")
88
+ @click.option("--agents", help="Comma-separated agent types")
89
+ def create_swarm(name: str, project_id: str, objective: str, agents: Optional[str]):
90
+ """Create a new swarm."""
91
+ try:
92
+ client = get_client()
93
+
94
+ agent_list = []
95
+ if agents:
96
+ for agent_type in agents.split(","):
97
+ agent_list.append({"type": agent_type.strip()})
98
+
99
+ result = client.agent_swarm.start_swarm(
100
+ project_id=project_id,
101
+ agents=agent_list,
102
+ objective=objective,
103
+ config={"name": name}
104
+ )
105
+
106
+ console.print(Panel(
107
+ f"[green]✓[/green] Swarm created: {result.get('swarm_id')}",
108
+ title="Success"
109
+ ))
110
+ console.print(json.dumps(result, indent=2))
111
+
112
+ except Exception as e:
113
+ click.echo(f"Error: {str(e)}", err=True)
114
+
115
+
116
+ @swarm_group.command(name="delete")
117
+ @click.argument("swarm_id")
118
+ @click.option("--force", is_flag=True, help="Force deletion without cleanup")
119
+ def delete_swarm(swarm_id: str, force: bool):
120
+ """Delete a swarm."""
121
+ try:
122
+ if not force:
123
+ click.confirm(f"Delete swarm {swarm_id}?", abort=True)
124
+
125
+ client = get_client()
126
+ result = client.agent_swarm.delete_swarm(swarm_id, force=force)
127
+
128
+ console.print(Panel(
129
+ f"[green]✓[/green] Swarm deleted: {swarm_id}",
130
+ title="Success"
131
+ ))
132
+
133
+ except Exception as e:
134
+ click.echo(f"Error: {str(e)}", err=True)
135
+
136
+
137
+ @swarm_group.command(name="scale")
138
+ @click.argument("swarm_id")
139
+ @click.option("--agents", required=True, help="Agent counts (e.g., researcher=5,coder=3)")
140
+ def scale_swarm(swarm_id: str, agents: str):
141
+ """Scale swarm agent counts."""
142
+ try:
143
+ agent_counts = {}
144
+ for pair in agents.split(","):
145
+ agent_type, count = pair.split("=")
146
+ agent_counts[agent_type.strip()] = int(count)
147
+
148
+ client = get_client()
149
+ result = client.agent_swarm.scale_swarm(swarm_id, agent_counts)
150
+
151
+ console.print(Panel(
152
+ f"[green]✓[/green] Swarm scaled successfully",
153
+ title="Success"
154
+ ))
155
+ console.print(json.dumps(result, indent=2))
156
+
157
+ except Exception as e:
158
+ click.echo(f"Error: {str(e)}", err=True)
159
+
160
+
161
+ @swarm_group.command(name="analytics")
162
+ @click.argument("swarm_id")
163
+ @click.option("--time-range", default="7d", help="Time range (1d, 7d, 30d, all)")
164
+ @click.option("--metrics", help="Comma-separated metric types")
165
+ def get_analytics(swarm_id: str, time_range: str, metrics: Optional[str]):
166
+ """Get swarm analytics."""
167
+ try:
168
+ client = get_client()
169
+
170
+ metric_list = metrics.split(",") if metrics else None
171
+ result = client.agent_swarm.get_analytics(
172
+ swarm_id,
173
+ metric_types=metric_list,
174
+ time_range=time_range
175
+ )
176
+
177
+ console.print(Panel(
178
+ f"Analytics for swarm: {swarm_id}",
179
+ title="Swarm Analytics"
180
+ ))
181
+ console.print(json.dumps(result, indent=2))
182
+
183
+ except Exception as e:
184
+ click.echo(f"Error: {str(e)}", err=True)
@@ -0,0 +1,157 @@
1
+ """
2
+ Sync CLI Commands
3
+
4
+ Commands for synchronizing local and cloud database environments.
5
+ """
6
+
7
+ import click
8
+ import json
9
+ from typing import Optional
10
+ from rich.console import Console
11
+
12
+ from ..client import AINativeClient
13
+ from ..cli_utils.diff import DatabaseDiff
14
+ from ..cli_utils.formatters import DiffFormatter
15
+
16
+
17
+ console = Console()
18
+
19
+
20
+ def get_client(base_url: Optional[str] = None) -> AINativeClient:
21
+ """Get authenticated client with optional base URL override."""
22
+ import os
23
+ from ..auth import AuthConfig
24
+
25
+ api_key = os.getenv("AINATIVE_API_KEY")
26
+ if not api_key:
27
+ raise click.ClickException("AINATIVE_API_KEY environment variable not set")
28
+
29
+ return AINativeClient(
30
+ auth_config=AuthConfig(api_key=api_key),
31
+ base_url=base_url,
32
+ organization_id=os.getenv("AINATIVE_ORG_ID")
33
+ )
34
+
35
+
36
+ @click.group(name="sync")
37
+ def sync_group():
38
+ """Database synchronization commands."""
39
+ pass
40
+
41
+
42
+ @sync_group.command(name="plan")
43
+ @click.option(
44
+ "--local-url",
45
+ default="http://localhost:8000",
46
+ help="Local API URL (default: http://localhost:8000)"
47
+ )
48
+ @click.option(
49
+ "--cloud-url",
50
+ default="https://api.ainative.studio",
51
+ help="Cloud API URL (default: https://api.ainative.studio)"
52
+ )
53
+ @click.option(
54
+ "--schema",
55
+ is_flag=True,
56
+ help="Show schema diff only"
57
+ )
58
+ @click.option(
59
+ "--data",
60
+ is_flag=True,
61
+ help="Show data diff only"
62
+ )
63
+ @click.option(
64
+ "--vectors",
65
+ is_flag=True,
66
+ help="Show vectors diff only"
67
+ )
68
+ @click.option(
69
+ "--json",
70
+ "json_output",
71
+ is_flag=True,
72
+ help="Output as JSON"
73
+ )
74
+ def sync_plan(
75
+ local_url: str,
76
+ cloud_url: str,
77
+ schema: bool,
78
+ data: bool,
79
+ vectors: bool,
80
+ json_output: bool
81
+ ):
82
+ """
83
+ Show diff between local and cloud environments.
84
+
85
+ Compares database schema, data, and vectors between local development
86
+ environment and cloud production. Use flags to filter specific types.
87
+
88
+ Examples:
89
+ ainative sync plan
90
+ ainative sync plan --schema
91
+ ainative sync plan --data --vectors
92
+ ainative sync plan --json
93
+ """
94
+ try:
95
+ # If no specific flags set, show all
96
+ show_all = not (schema or data or vectors)
97
+
98
+ console.print("\n[bold cyan]🔍 Sync Plan (Local → Cloud)[/bold cyan]\n")
99
+
100
+ # Fetch data from local and cloud
101
+ console.print("[dim]Fetching local database state...[/dim]")
102
+ local_client = get_client(local_url)
103
+
104
+ console.print("[dim]Fetching cloud database state...[/dim]")
105
+ cloud_client = get_client(cloud_url)
106
+
107
+ # Compute diffs
108
+ differ = DatabaseDiff(local_client, cloud_client)
109
+
110
+ # Get schema diff
111
+ schema_diff = None
112
+ if show_all or schema:
113
+ schema_diff = differ.compute_schema_diff()
114
+
115
+ # Get data diff
116
+ data_diff = None
117
+ if show_all or data:
118
+ data_diff = differ.compute_data_diff()
119
+
120
+ # Get vectors diff
121
+ vectors_diff = None
122
+ if show_all or vectors:
123
+ vectors_diff = differ.compute_vectors_diff()
124
+
125
+ # Format and display output
126
+ formatter = DiffFormatter()
127
+
128
+ if json_output:
129
+ # JSON output
130
+ output = {
131
+ "schema": schema_diff,
132
+ "data": data_diff,
133
+ "vectors": vectors_diff
134
+ }
135
+ click.echo(json.dumps(output, indent=2))
136
+ else:
137
+ # Rich formatted output
138
+ if schema_diff:
139
+ formatter.format_schema_diff(schema_diff)
140
+
141
+ if data_diff:
142
+ formatter.format_data_diff(data_diff)
143
+
144
+ if vectors_diff:
145
+ formatter.format_vectors_diff(vectors_diff)
146
+
147
+ # Show summary
148
+ console.print("\n[dim]Use `ainative sync apply` to execute.[/dim]")
149
+
150
+ except click.ClickException:
151
+ raise
152
+ except Exception as e:
153
+ console.print(f"[red]Error:[/red] {str(e)}")
154
+ if "--verbose" in click.get_current_context().args:
155
+ import traceback
156
+ console.print(traceback.format_exc())
157
+ raise click.Abort()
@@ -0,0 +1,191 @@
1
+ """
2
+ Task Execution CLI Commands
3
+
4
+ Commands for task management (create, execute, status, list, sequence).
5
+ """
6
+
7
+ import click
8
+ import json
9
+ from typing import Optional
10
+ from rich.console import Console
11
+ from rich.table import Table
12
+ from rich.panel import Panel
13
+ from rich import print as rprint
14
+
15
+ from ..client import AINativeClient
16
+
17
+
18
+ console = Console()
19
+
20
+
21
+ def get_client() -> AINativeClient:
22
+ """Get authenticated client."""
23
+ import os
24
+ from ..auth import AuthConfig
25
+
26
+ api_key = os.getenv("AINATIVE_API_KEY")
27
+ if not api_key:
28
+ raise click.ClickException("AINATIVE_API_KEY environment variable not set")
29
+
30
+ return AINativeClient(
31
+ auth_config=AuthConfig(api_key=api_key),
32
+ base_url=os.getenv("AINATIVE_BASE_URL"),
33
+ organization_id=os.getenv("AINATIVE_ORG_ID")
34
+ )
35
+
36
+
37
+ @click.group(name="task")
38
+ def task_group():
39
+ """Manage agent tasks."""
40
+ pass
41
+
42
+
43
+ @task_group.command(name="create")
44
+ @click.option("--agent-id", required=True, help="Agent instance ID")
45
+ @click.option("--type", "task_type", required=True, help="Task type")
46
+ @click.option("--description", required=True, help="Task description")
47
+ @click.option("--priority", default="medium", help="Task priority (low, medium, high, critical)")
48
+ @click.option("--context", help="Task context as JSON string")
49
+ def create_task(agent_id: str, task_type: str, description: str, priority: str, context: Optional[str]):
50
+ """Create a new task."""
51
+ try:
52
+ client = get_client()
53
+
54
+ context_data = {}
55
+ if context:
56
+ context_data = json.loads(context)
57
+
58
+ result = client.agent_orchestration.create_task(
59
+ agent_id=agent_id,
60
+ task_type=task_type,
61
+ description=description,
62
+ context=context_data,
63
+ priority=priority
64
+ )
65
+
66
+ console.print(Panel(
67
+ f"[green]✓[/green] Task created: {result.get('task_id')}",
68
+ title="Success"
69
+ ))
70
+ console.print(json.dumps(result, indent=2))
71
+
72
+ except Exception as e:
73
+ click.echo(f"Error: {str(e)}", err=True)
74
+
75
+
76
+ @task_group.command(name="execute")
77
+ @click.argument("task_id")
78
+ @click.option("--agent-id", help="Optional specific agent to use")
79
+ def execute_task(task_id: str, agent_id: Optional[str]):
80
+ """Execute a task."""
81
+ try:
82
+ client = get_client()
83
+ result = client.agent_orchestration.execute_task(task_id, agent_id=agent_id)
84
+
85
+ console.print(Panel(
86
+ f"[green]✓[/green] Task execution started",
87
+ title="Success"
88
+ ))
89
+ console.print(json.dumps(result, indent=2))
90
+
91
+ except Exception as e:
92
+ click.echo(f"Error: {str(e)}", err=True)
93
+
94
+
95
+ @task_group.command(name="status")
96
+ @click.argument("task_id")
97
+ def get_status(task_id: str):
98
+ """Get task status."""
99
+ try:
100
+ client = get_client()
101
+ result = client.agent_orchestration.get_task_status(task_id)
102
+
103
+ status = result.get("status", "unknown")
104
+ status_color = {
105
+ "pending": "yellow",
106
+ "running": "blue",
107
+ "completed": "green",
108
+ "failed": "red"
109
+ }.get(status, "white")
110
+
111
+ console.print(Panel(
112
+ f"Status: [{status_color}]{status}[/{status_color}]\n\n" +
113
+ json.dumps(result, indent=2),
114
+ title=f"Task {task_id}"
115
+ ))
116
+
117
+ except Exception as e:
118
+ click.echo(f"Error: {str(e)}", err=True)
119
+
120
+
121
+ @task_group.command(name="list")
122
+ @click.option("--agent-id", help="Filter by agent ID")
123
+ @click.option("--status", help="Filter by status")
124
+ @click.option("--type", "task_type", help="Filter by task type")
125
+ @click.option("--format", type=click.Choice(["table", "json"]), default="table",
126
+ help="Output format")
127
+ def list_tasks(agent_id: Optional[str], status: Optional[str], task_type: Optional[str], format: str):
128
+ """List tasks."""
129
+ try:
130
+ client = get_client()
131
+ result = client.agent_orchestration.list_tasks(
132
+ agent_id=agent_id,
133
+ status=status,
134
+ task_type=task_type
135
+ )
136
+
137
+ tasks = result.get("tasks", [])
138
+
139
+ if format == "json":
140
+ click.echo(json.dumps(tasks, indent=2))
141
+ else:
142
+ table = Table(title="Tasks")
143
+ table.add_column("ID", style="cyan")
144
+ table.add_column("Type", style="bold")
145
+ table.add_column("Status", style="green")
146
+ table.add_column("Priority", justify="right")
147
+ table.add_column("Agent", style="dim")
148
+
149
+ for task in tasks:
150
+ table.add_row(
151
+ task.get("id", "")[:12],
152
+ task.get("task_type", ""),
153
+ task.get("status", ""),
154
+ task.get("priority", ""),
155
+ task.get("agent_id", "")[:12]
156
+ )
157
+
158
+ console.print(table)
159
+ console.print(f"\nTotal: {len(tasks)} tasks")
160
+
161
+ except Exception as e:
162
+ click.echo(f"Error: {str(e)}", err=True)
163
+
164
+
165
+ @task_group.command(name="sequence")
166
+ @click.option("--name", required=True, help="Sequence name")
167
+ @click.option("--tasks", required=True, help="Task IDs (comma-separated)")
168
+ @click.option("--mode", default="sequential", help="Execution mode (sequential, parallel, conditional)")
169
+ def create_sequence(name: str, tasks: str, mode: str):
170
+ """Create a task sequence."""
171
+ try:
172
+ client = get_client()
173
+
174
+ task_list = []
175
+ for task_id in tasks.split(","):
176
+ task_list.append({"task_id": task_id.strip()})
177
+
178
+ result = client.agent_coordination.create_task_sequence(
179
+ name=name,
180
+ tasks=task_list,
181
+ execution_mode=mode
182
+ )
183
+
184
+ console.print(Panel(
185
+ f"[green]✓[/green] Sequence created: {result.get('sequence_id')}",
186
+ title="Success"
187
+ ))
188
+ console.print(json.dumps(result, indent=2))
189
+
190
+ except Exception as e:
191
+ click.echo(f"Error: {str(e)}", err=True)
ainative/exceptions.py ADDED
@@ -0,0 +1,87 @@
1
+ """
2
+ AINative SDK Exception Classes
3
+
4
+ Custom exceptions for better error handling and debugging.
5
+ """
6
+
7
+ from typing import Optional, Dict, Any
8
+
9
+
10
+ class AINativeException(Exception):
11
+ """Base exception for all AINative SDK errors."""
12
+
13
+ def __init__(
14
+ self,
15
+ message: str,
16
+ error_code: Optional[str] = None,
17
+ details: Optional[Dict[str, Any]] = None,
18
+ ):
19
+ super().__init__(message)
20
+ self.message = message
21
+ self.error_code = error_code
22
+ self.details = details or {}
23
+
24
+
25
+ class AuthenticationError(AINativeException):
26
+ """Raised when authentication fails."""
27
+
28
+ def __init__(self, message: str = "Authentication failed"):
29
+ super().__init__(message, error_code="AUTH_ERROR")
30
+
31
+
32
+ class APIError(AINativeException):
33
+ """Raised when API returns an error response."""
34
+
35
+ def __init__(
36
+ self,
37
+ message: str,
38
+ status_code: Optional[int] = None,
39
+ response_body: Optional[str] = None,
40
+ ):
41
+ super().__init__(message, error_code="API_ERROR")
42
+ self.status_code = status_code
43
+ self.response_body = response_body
44
+
45
+
46
+ class NetworkError(AINativeException):
47
+ """Raised when network-related errors occur."""
48
+
49
+ def __init__(self, message: str = "Network error occurred"):
50
+ super().__init__(message, error_code="NETWORK_ERROR")
51
+
52
+
53
+ class ValidationError(AINativeException):
54
+ """Raised when input validation fails."""
55
+
56
+ def __init__(self, message: str, field: Optional[str] = None):
57
+ super().__init__(message, error_code="VALIDATION_ERROR")
58
+ self.field = field
59
+
60
+
61
+ class RateLimitError(AINativeException):
62
+ """Raised when API rate limit is exceeded."""
63
+
64
+ def __init__(
65
+ self,
66
+ message: str = "Rate limit exceeded",
67
+ retry_after: Optional[int] = None,
68
+ ):
69
+ super().__init__(message, error_code="RATE_LIMIT")
70
+ self.retry_after = retry_after
71
+
72
+
73
+ class ResourceNotFoundError(AINativeException):
74
+ """Raised when requested resource is not found."""
75
+
76
+ def __init__(self, resource_type: str, resource_id: str):
77
+ message = f"{resource_type} with ID {resource_id} not found"
78
+ super().__init__(message, error_code="NOT_FOUND")
79
+ self.resource_type = resource_type
80
+ self.resource_id = resource_id
81
+
82
+
83
+ class TimeoutError(AINativeException):
84
+ """Raised when operation times out."""
85
+
86
+ def __init__(self, message: str = "Operation timed out"):
87
+ super().__init__(message, error_code="TIMEOUT")
@@ -0,0 +1,89 @@
1
+ """
2
+ ZeroDB Module for AINative SDK
3
+
4
+ Provides high-level interface for ZeroDB operations including projects,
5
+ vectors, memory, and analytics.
6
+ """
7
+
8
+ from typing import TYPE_CHECKING, List, Dict, Any, Optional
9
+ from datetime import datetime
10
+
11
+ if TYPE_CHECKING:
12
+ from ..client import AINativeClient
13
+
14
+ from .projects import ProjectsClient
15
+ from .vectors import VectorsClient
16
+ from .memory import MemoryClient
17
+ from .analytics import AnalyticsClient
18
+ from .tables import TablesClient
19
+
20
+
21
+ class ZeroDBClient:
22
+ """Main client for ZeroDB operations."""
23
+
24
+ def __init__(self, client: "AINativeClient"):
25
+ """
26
+ Initialize ZeroDB client.
27
+
28
+ Args:
29
+ client: Parent AINative client instance
30
+ """
31
+ self.client = client
32
+ self._projects: Optional[ProjectsClient] = None
33
+ self._vectors: Optional[VectorsClient] = None
34
+ self._memory: Optional[MemoryClient] = None
35
+ self._analytics: Optional[AnalyticsClient] = None
36
+ self._tables: Optional[TablesClient] = None
37
+
38
+ @property
39
+ def projects(self) -> ProjectsClient:
40
+ """Get projects operations client."""
41
+ if not self._projects:
42
+ self._projects = ProjectsClient(self.client)
43
+ return self._projects
44
+
45
+ @property
46
+ def vectors(self) -> VectorsClient:
47
+ """Get vectors operations client."""
48
+ if not self._vectors:
49
+ self._vectors = VectorsClient(self.client)
50
+ return self._vectors
51
+
52
+ @property
53
+ def memory(self) -> MemoryClient:
54
+ """Get memory operations client."""
55
+ if not self._memory:
56
+ self._memory = MemoryClient(self.client)
57
+ return self._memory
58
+
59
+ @property
60
+ def analytics(self) -> AnalyticsClient:
61
+ """Get analytics operations client."""
62
+ if not self._analytics:
63
+ self._analytics = AnalyticsClient(self.client)
64
+ return self._analytics
65
+
66
+ @property
67
+ def tables(self) -> TablesClient:
68
+ """Get NoSQL tables operations client."""
69
+ if not self._tables:
70
+ self._tables = TablesClient(self.client)
71
+ return self._tables
72
+
73
+ def health_check(self) -> Dict[str, Any]:
74
+ """Check ZeroDB health status."""
75
+ return self.client.get("/zerodb/health")
76
+
77
+ def get_usage_stats(self) -> Dict[str, Any]:
78
+ """Get usage statistics for ZeroDB."""
79
+ return self.client.get("/zerodb/usage")
80
+
81
+
82
+ __all__ = [
83
+ "ZeroDBClient",
84
+ "ProjectsClient",
85
+ "VectorsClient",
86
+ "MemoryClient",
87
+ "AnalyticsClient",
88
+ "TablesClient",
89
+ ]