ainative-python 2.0.0__py3-none-any.whl → 3.1.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.
ainative/__init__.py CHANGED
@@ -2,9 +2,14 @@
2
2
  AINative Python SDK
3
3
 
4
4
  Official Python SDK for AINative Studio APIs including ZeroDB and Agent Swarm operations.
5
+
6
+ ⚠️ BREAKING CHANGES IN v3.0.0:
7
+ - All ZeroDB endpoint paths updated to canonical routes
8
+ - table/memory/analytics methods now require project_id as first parameter
9
+ - See CHANGELOG.md for migration guide
5
10
  """
6
11
 
7
- __version__ = "2.0.0"
12
+ __version__ = "3.1.0"
8
13
  __author__ = "AINative Team"
9
14
  __email__ = "support@ainative.studio"
10
15
 
ainative/auth.py CHANGED
@@ -56,7 +56,7 @@ class APIKeyAuth:
56
56
 
57
57
  headers = {
58
58
  "X-API-Key": self.config.api_key,
59
- "X-SDK-Version": "0.1.0",
59
+ "X-SDK-Version": "3.0.0",
60
60
  "X-SDK-Language": "Python",
61
61
  }
62
62
 
@@ -13,152 +13,139 @@ if TYPE_CHECKING:
13
13
 
14
14
  class AnalyticsClient:
15
15
  """Client for ZeroDB analytics operations."""
16
-
16
+
17
17
  def __init__(self, client: "AINativeClient"):
18
18
  """
19
19
  Initialize analytics client.
20
-
20
+
21
21
  Args:
22
22
  client: Parent AINative client instance
23
23
  """
24
24
  self.client = client
25
- self.base_path = "/zerodb/analytics"
25
+ # Analytics are accessed via /projects/{project_id}/database/analytics/*
26
+ self.base_path = "/projects"
26
27
 
27
28
  def get_usage(
28
29
  self,
29
- project_id: Optional[str] = None,
30
+ project_id: str,
30
31
  start_date: Optional[datetime] = None,
31
32
  end_date: Optional[datetime] = None,
32
33
  granularity: str = "daily",
33
34
  ) -> Dict[str, Any]:
34
35
  """
35
36
  Get usage analytics.
36
-
37
+
37
38
  Args:
38
- project_id: Optional project ID filter
39
+ project_id: Project ID (required)
39
40
  start_date: Start date for analytics
40
41
  end_date: End date for analytics
41
42
  granularity: Data granularity (hourly, daily, weekly, monthly)
42
-
43
+
43
44
  Returns:
44
45
  Usage analytics data
45
46
  """
46
47
  params = {"granularity": granularity}
47
-
48
- if project_id:
49
- params["project_id"] = project_id
48
+
50
49
  if start_date:
51
50
  params["start_date"] = start_date.isoformat()
52
51
  if end_date:
53
52
  params["end_date"] = end_date.isoformat()
54
-
55
- return self.client.get(f"{self.base_path}/usage", params=params)
53
+
54
+ return self.client.get(f"{self.base_path}/{project_id}/database/analytics/usage", params=params)
56
55
 
57
56
  def get_performance_metrics(
58
57
  self,
59
- project_id: Optional[str] = None,
58
+ project_id: str,
60
59
  metric_type: str = "all",
61
60
  ) -> Dict[str, Any]:
62
61
  """
63
62
  Get performance metrics.
64
-
63
+
65
64
  Args:
66
- project_id: Optional project ID filter
65
+ project_id: Project ID (required)
67
66
  metric_type: Type of metrics (latency, throughput, errors, all)
68
-
67
+
69
68
  Returns:
70
69
  Performance metrics data
71
70
  """
72
71
  params = {"metric_type": metric_type}
73
-
74
- if project_id:
75
- params["project_id"] = project_id
76
-
77
- return self.client.get(f"{self.base_path}/performance", params=params)
72
+
73
+ return self.client.get(f"{self.base_path}/{project_id}/database/analytics/performance", params=params)
78
74
 
79
75
  def get_storage_stats(
80
76
  self,
81
- project_id: Optional[str] = None,
77
+ project_id: str,
82
78
  ) -> Dict[str, Any]:
83
79
  """
84
80
  Get storage statistics.
85
-
81
+
86
82
  Args:
87
- project_id: Optional project ID filter
88
-
83
+ project_id: Project ID (required)
84
+
89
85
  Returns:
90
86
  Storage statistics including size, vector count, etc.
91
87
  """
92
- params = {}
93
- if project_id:
94
- params["project_id"] = project_id
95
-
96
- return self.client.get(f"{self.base_path}/storage", params=params)
88
+ return self.client.get(f"{self.base_path}/{project_id}/database/analytics/storage")
97
89
 
98
90
  def get_query_insights(
99
91
  self,
100
- project_id: Optional[str] = None,
92
+ project_id: str,
101
93
  limit: int = 100,
102
94
  ) -> Dict[str, Any]:
103
95
  """
104
96
  Get query pattern insights.
105
-
97
+
106
98
  Args:
107
- project_id: Optional project ID filter
99
+ project_id: Project ID (required)
108
100
  limit: Maximum number of insights
109
-
101
+
110
102
  Returns:
111
103
  Query insights and patterns
112
104
  """
113
105
  params = {"limit": limit}
114
-
115
- if project_id:
116
- params["project_id"] = project_id
117
-
118
- return self.client.get(f"{self.base_path}/queries", params=params)
106
+
107
+ return self.client.get(f"{self.base_path}/{project_id}/database/analytics/queries", params=params)
119
108
 
120
109
  def get_cost_analysis(
121
110
  self,
122
- project_id: Optional[str] = None,
111
+ project_id: str,
123
112
  start_date: Optional[datetime] = None,
124
113
  end_date: Optional[datetime] = None,
125
114
  ) -> Dict[str, Any]:
126
115
  """
127
116
  Get cost analysis and projections.
128
-
117
+
129
118
  Args:
130
- project_id: Optional project ID filter
119
+ project_id: Project ID (required)
131
120
  start_date: Start date for analysis
132
121
  end_date: End date for analysis
133
-
122
+
134
123
  Returns:
135
124
  Cost analysis data
136
125
  """
137
126
  params = {}
138
-
139
- if project_id:
140
- params["project_id"] = project_id
127
+
141
128
  if start_date:
142
129
  params["start_date"] = start_date.isoformat()
143
130
  if end_date:
144
131
  params["end_date"] = end_date.isoformat()
145
-
146
- return self.client.get(f"{self.base_path}/costs", params=params)
132
+
133
+ return self.client.get(f"{self.base_path}/{project_id}/database/analytics/costs", params=params)
147
134
 
148
135
  def get_trends(
149
136
  self,
137
+ project_id: str,
150
138
  metric: str,
151
- project_id: Optional[str] = None,
152
139
  period: int = 30,
153
140
  ) -> List[Dict[str, Any]]:
154
141
  """
155
142
  Get trend data for specific metrics.
156
-
143
+
157
144
  Args:
145
+ project_id: Project ID (required)
158
146
  metric: Metric name (vectors, queries, storage, errors)
159
- project_id: Optional project ID filter
160
147
  period: Number of days to analyze
161
-
148
+
162
149
  Returns:
163
150
  Trend data points
164
151
  """
@@ -166,54 +153,48 @@ class AnalyticsClient:
166
153
  "metric": metric,
167
154
  "period": period,
168
155
  }
169
-
170
- if project_id:
171
- params["project_id"] = project_id
172
-
173
- response = self.client.get(f"{self.base_path}/trends", params=params)
156
+
157
+ response = self.client.get(f"{self.base_path}/{project_id}/database/analytics/trends", params=params)
174
158
  return response.get("data", [])
175
159
 
176
160
  def get_anomalies(
177
161
  self,
178
- project_id: Optional[str] = None,
162
+ project_id: str,
179
163
  severity: str = "all",
180
164
  ) -> List[Dict[str, Any]]:
181
165
  """
182
166
  Get detected anomalies in usage patterns.
183
-
167
+
184
168
  Args:
185
- project_id: Optional project ID filter
169
+ project_id: Project ID (required)
186
170
  severity: Severity filter (low, medium, high, critical, all)
187
-
171
+
188
172
  Returns:
189
173
  List of detected anomalies
190
174
  """
191
175
  params = {"severity": severity}
192
-
193
- if project_id:
194
- params["project_id"] = project_id
195
-
196
- response = self.client.get(f"{self.base_path}/anomalies", params=params)
176
+
177
+ response = self.client.get(f"{self.base_path}/{project_id}/database/analytics/anomalies", params=params)
197
178
  return response.get("anomalies", [])
198
179
 
199
180
  def export_report(
200
181
  self,
182
+ project_id: str,
201
183
  report_type: str = "summary",
202
- project_id: Optional[str] = None,
203
184
  format: str = "json",
204
185
  start_date: Optional[datetime] = None,
205
186
  end_date: Optional[datetime] = None,
206
187
  ) -> Dict[str, Any]:
207
188
  """
208
189
  Export analytics report.
209
-
190
+
210
191
  Args:
192
+ project_id: Project ID (required)
211
193
  report_type: Type of report (summary, detailed, custom)
212
- project_id: Optional project ID filter
213
194
  format: Export format (json, csv, pdf)
214
195
  start_date: Start date for report
215
196
  end_date: End date for report
216
-
197
+
217
198
  Returns:
218
199
  Report data or download URL
219
200
  """
@@ -221,12 +202,10 @@ class AnalyticsClient:
221
202
  "report_type": report_type,
222
203
  "format": format,
223
204
  }
224
-
225
- if project_id:
226
- data["project_id"] = project_id
205
+
227
206
  if start_date:
228
207
  data["start_date"] = start_date.isoformat()
229
208
  if end_date:
230
209
  data["end_date"] = end_date.isoformat()
231
-
232
- return self.client.post(f"{self.base_path}/export", data=data)
210
+
211
+ return self.client.post(f"{self.base_path}/{project_id}/database/analytics/export", data=data)
ainative/zerodb/memory.py CHANGED
@@ -26,39 +26,46 @@ class MemoryClient:
26
26
  def __init__(self, client: "AINativeClient"):
27
27
  """
28
28
  Initialize memory client.
29
-
29
+
30
30
  Args:
31
31
  client: Parent AINative client instance
32
32
  """
33
33
  self.client = client
34
- self.base_path = "/zerodb/memory"
34
+ self.base_path = "/projects"
35
35
 
36
36
  def create(
37
37
  self,
38
+ project_id: str,
38
39
  content: str,
39
40
  title: Optional[str] = None,
40
41
  tags: Optional[List[str]] = None,
41
42
  priority: MemoryPriority = MemoryPriority.MEDIUM,
42
43
  metadata: Optional[Dict[str, Any]] = None,
43
- project_id: Optional[str] = None,
44
44
  user_id: Optional[str] = None,
45
45
  expires_at: Optional[datetime] = None,
46
46
  ) -> Dict[str, Any]:
47
47
  """
48
48
  Create a new memory entry.
49
-
49
+
50
50
  Args:
51
+ project_id: Project ID (required)
51
52
  content: Memory content
52
53
  title: Memory title
53
54
  tags: List of tags
54
55
  priority: Memory priority level
55
56
  metadata: Additional metadata
56
- project_id: Associated project ID
57
57
  user_id: Associated user ID
58
58
  expires_at: Expiration timestamp
59
-
59
+
60
60
  Returns:
61
61
  Created memory details
62
+
63
+ Example:
64
+ >>> memory = client.zerodb.memory.create(
65
+ ... PROJECT_ID,
66
+ ... content="User prefers dark mode",
67
+ ... tags=["preferences", "ui"]
68
+ ... )
62
69
  """
63
70
  data = {
64
71
  "content": content,
@@ -67,21 +74,19 @@ class MemoryClient:
67
74
  "priority": priority.value,
68
75
  "metadata": metadata or {},
69
76
  }
70
-
71
- if project_id:
72
- data["project_id"] = project_id
77
+
73
78
  if user_id:
74
79
  data["user_id"] = user_id
75
80
  if expires_at:
76
81
  data["expires_at"] = expires_at.isoformat()
77
-
78
- return self.client.post(self.base_path, data=data)
82
+
83
+ return self.client.post(f"{self.base_path}/{project_id}/database/memory", data=data)
79
84
 
80
85
  def list(
81
86
  self,
87
+ project_id: str,
82
88
  limit: int = 100,
83
89
  offset: int = 0,
84
- project_id: Optional[str] = None,
85
90
  user_id: Optional[str] = None,
86
91
  tags: Optional[List[str]] = None,
87
92
  priority: Optional[MemoryPriority] = None,
@@ -89,26 +94,27 @@ class MemoryClient:
89
94
  ) -> Dict[str, Any]:
90
95
  """
91
96
  List memory entries.
92
-
97
+
93
98
  Args:
99
+ project_id: Project ID (required)
94
100
  limit: Maximum number of entries to return
95
101
  offset: Number of entries to skip
96
- project_id: Filter by project ID
97
102
  user_id: Filter by user ID
98
103
  tags: Filter by tags
99
104
  priority: Filter by priority
100
105
  search: Search query
101
-
106
+
102
107
  Returns:
103
108
  Dictionary containing memories list and pagination info
109
+
110
+ Example:
111
+ >>> memories = client.zerodb.memory.list(PROJECT_ID, limit=50)
104
112
  """
105
113
  params = {
106
114
  "limit": limit,
107
115
  "offset": offset,
108
116
  }
109
-
110
- if project_id:
111
- params["project_id"] = project_id
117
+
112
118
  if user_id:
113
119
  params["user_id"] = user_id
114
120
  if tags:
@@ -117,23 +123,25 @@ class MemoryClient:
117
123
  params["priority"] = priority.value
118
124
  if search:
119
125
  params["search"] = search
120
-
121
- return self.client.get(f"{self.base_path}ies", params=params)
126
+
127
+ return self.client.get(f"{self.base_path}/{project_id}/database/memory", params=params)
122
128
 
123
- def get(self, memory_id: str) -> Dict[str, Any]:
129
+ def get(self, project_id: str, memory_id: str) -> Dict[str, Any]:
124
130
  """
125
131
  Get a specific memory entry.
126
-
132
+
127
133
  Args:
134
+ project_id: Project ID (required)
128
135
  memory_id: Memory ID
129
-
136
+
130
137
  Returns:
131
138
  Memory details
132
139
  """
133
- return self.client.get(f"{self.base_path}/{memory_id}")
140
+ return self.client.get(f"{self.base_path}/{project_id}/database/memory/{memory_id}")
134
141
 
135
142
  def update(
136
143
  self,
144
+ project_id: str,
137
145
  memory_id: str,
138
146
  content: Optional[str] = None,
139
147
  title: Optional[str] = None,
@@ -143,15 +151,16 @@ class MemoryClient:
143
151
  ) -> Dict[str, Any]:
144
152
  """
145
153
  Update a memory entry.
146
-
154
+
147
155
  Args:
156
+ project_id: Project ID (required)
148
157
  memory_id: Memory ID
149
158
  content: New content
150
159
  title: New title
151
160
  tags: New tags
152
161
  priority: New priority
153
162
  metadata: New metadata
154
-
163
+
155
164
  Returns:
156
165
  Updated memory details
157
166
  """
@@ -166,95 +175,100 @@ class MemoryClient:
166
175
  data["priority"] = priority.value
167
176
  if metadata is not None:
168
177
  data["metadata"] = metadata
169
-
170
- return self.client.patch(f"{self.base_path}/{memory_id}", data=data)
178
+
179
+ return self.client.patch(f"{self.base_path}/{project_id}/database/memory/{memory_id}", data=data)
171
180
 
172
- def delete(self, memory_id: str) -> Dict[str, Any]:
181
+ def delete(self, project_id: str, memory_id: str) -> Dict[str, Any]:
173
182
  """
174
183
  Delete a memory entry.
175
-
184
+
176
185
  Args:
186
+ project_id: Project ID (required)
177
187
  memory_id: Memory ID
178
-
188
+
179
189
  Returns:
180
190
  Deletion confirmation
181
191
  """
182
- return self.client.delete(f"{self.base_path}/{memory_id}")
192
+ return self.client.delete(f"{self.base_path}/{project_id}/database/memory/{memory_id}")
183
193
 
184
194
  def search(
185
195
  self,
196
+ project_id: str,
186
197
  query: str,
187
198
  limit: int = 10,
188
- project_id: Optional[str] = None,
189
199
  user_id: Optional[str] = None,
190
200
  semantic: bool = True,
191
201
  ) -> List[Dict[str, Any]]:
192
202
  """
193
203
  Search memories using text or semantic search.
194
-
204
+
195
205
  Args:
206
+ project_id: Project ID (required)
196
207
  query: Search query
197
208
  limit: Maximum number of results
198
- project_id: Filter by project ID
199
209
  user_id: Filter by user ID
200
210
  semantic: Use semantic search (if False, uses text search)
201
-
211
+
202
212
  Returns:
203
213
  List of matching memories
214
+
215
+ Example:
216
+ >>> results = client.zerodb.memory.search(
217
+ ... PROJECT_ID,
218
+ ... query="What does user prefer?",
219
+ ... top_k=5
220
+ ... )
204
221
  """
205
222
  data = {
206
223
  "query": query,
207
224
  "limit": limit,
208
225
  "semantic": semantic,
209
226
  }
210
-
211
- if project_id:
212
- data["project_id"] = project_id
227
+
213
228
  if user_id:
214
229
  data["user_id"] = user_id
215
-
216
- response = self.client.post(f"{self.base_path}/search", data=data)
230
+
231
+ response = self.client.post(f"{self.base_path}/{project_id}/database/memory/search", data=data)
217
232
  return response.get("results", [])
218
233
 
219
234
  def bulk_create(
220
235
  self,
236
+ project_id: str,
221
237
  memories: List[Dict[str, Any]],
222
- project_id: Optional[str] = None,
223
238
  ) -> Dict[str, Any]:
224
239
  """
225
240
  Create multiple memory entries at once.
226
-
241
+
227
242
  Args:
243
+ project_id: Project ID (required)
228
244
  memories: List of memory data dictionaries
229
- project_id: Project ID for all memories
230
-
245
+
231
246
  Returns:
232
247
  Bulk creation result
233
248
  """
234
249
  data = {
235
250
  "memories": memories,
236
251
  }
237
-
238
- if project_id:
239
- data["project_id"] = project_id
240
-
241
- return self.client.post(f"{self.base_path}/bulk", data=data)
252
+
253
+ return self.client.post(f"{self.base_path}/{project_id}/database/memory/bulk", data=data)
242
254
 
243
255
  def get_related(
244
256
  self,
257
+ project_id: str,
245
258
  memory_id: str,
246
259
  limit: int = 5,
247
260
  ) -> List[Dict[str, Any]]:
248
261
  """
249
262
  Get memories related to a specific memory.
250
-
263
+
251
264
  Args:
265
+ project_id: Project ID (required)
252
266
  memory_id: Memory ID
253
267
  limit: Maximum number of related memories
254
-
268
+
255
269
  Returns:
256
270
  List of related memories
257
271
  """
258
272
  params = {"limit": limit}
259
- response = self.client.get(f"{self.base_path}/{memory_id}/related", params=params)
273
+ response = self.client.get(f"{self.base_path}/{project_id}/database/memory/{memory_id}/related", params=params)
260
274
  return response.get("memories", [])
@@ -26,12 +26,12 @@ class ProjectsClient:
26
26
  def __init__(self, client: "AINativeClient"):
27
27
  """
28
28
  Initialize projects client.
29
-
29
+
30
30
  Args:
31
31
  client: Parent AINative client instance
32
32
  """
33
33
  self.client = client
34
- self.base_path = "/zerodb/projects"
34
+ self.base_path = "/projects"
35
35
 
36
36
  def list(
37
37
  self,
ainative/zerodb/tables.py CHANGED
@@ -21,12 +21,14 @@ class TablesClient:
21
21
  client: Parent AINative client instance
22
22
  """
23
23
  self.client = client
24
- self.base_path = "/zerodb/tables"
24
+ # Tables are accessed via /projects/{project_id}/database/tables/*
25
+ self.base_path = "/projects"
25
26
 
26
27
  # Table Management Operations
27
28
 
28
29
  def create_table(
29
30
  self,
31
+ project_id: str,
30
32
  table_name: str,
31
33
  schema: Dict[str, Any],
32
34
  description: Optional[str] = None,
@@ -35,6 +37,7 @@ class TablesClient:
35
37
  Create a new NoSQL table.
36
38
 
37
39
  Args:
40
+ project_id: Project ID (required)
38
41
  table_name: Unique table name
39
42
  schema: Table schema definition with fields and indexes
40
43
  Example: {
@@ -52,6 +55,7 @@ class TablesClient:
52
55
 
53
56
  Example:
54
57
  >>> client.zerodb.tables.create_table(
58
+ ... PROJECT_ID,
55
59
  ... "users",
56
60
  ... schema={
57
61
  ... "fields": {"email": "string", "name": "string", "age": "number"},
@@ -67,10 +71,11 @@ class TablesClient:
67
71
  if description:
68
72
  data["description"] = description
69
73
 
70
- return self.client.post(self.base_path, data=data)
74
+ return self.client.post(f"{self.base_path}/{project_id}/database/tables", data=data)
71
75
 
72
76
  def list_tables(
73
77
  self,
78
+ project_id: str,
74
79
  limit: int = 100,
75
80
  offset: int = 0,
76
81
  ) -> Dict[str, Any]:
@@ -78,6 +83,7 @@ class TablesClient:
78
83
  List all tables in the project.
79
84
 
80
85
  Args:
86
+ project_id: Project ID (required)
81
87
  limit: Maximum number of results (default: 100)
82
88
  offset: Pagination offset (default: 0)
83
89
 
@@ -85,7 +91,7 @@ class TablesClient:
85
91
  Dictionary with 'tables' list and 'total' count
86
92
 
87
93
  Example:
88
- >>> tables = client.zerodb.tables.list_tables(limit=50)
94
+ >>> tables = client.zerodb.tables.list_tables(PROJECT_ID, limit=50)
89
95
  >>> for table in tables['tables']:
90
96
  ... print(f"{table['table_name']}: {table['row_count']} rows")
91
97
  """
@@ -94,30 +100,33 @@ class TablesClient:
94
100
  "offset": offset,
95
101
  }
96
102
 
97
- return self.client.get(self.base_path, params=params)
103
+ return self.client.get(f"{self.base_path}/{project_id}/database/tables", params=params)
98
104
 
99
105
  def get_table(
100
106
  self,
107
+ project_id: str,
101
108
  table_id: str,
102
109
  ) -> Dict[str, Any]:
103
110
  """
104
111
  Get table details and metadata.
105
112
 
106
113
  Args:
114
+ project_id: Project ID (required)
107
115
  table_id: Table ID or table name
108
116
 
109
117
  Returns:
110
118
  Table details including schema, row_count, and statistics
111
119
 
112
120
  Example:
113
- >>> table = client.zerodb.tables.get_table("users")
121
+ >>> table = client.zerodb.tables.get_table(PROJECT_ID, "users")
114
122
  >>> print(f"Schema: {table['schema']}")
115
123
  >>> print(f"Rows: {table['row_count']}")
116
124
  """
117
- return self.client.get(f"{self.base_path}/{table_id}")
125
+ return self.client.get(f"{self.base_path}/{project_id}/database/tables/{table_id}")
118
126
 
119
127
  def delete_table(
120
128
  self,
129
+ project_id: str,
121
130
  table_id: str,
122
131
  confirm: bool = False,
123
132
  ) -> Dict[str, Any]:
@@ -125,6 +134,7 @@ class TablesClient:
125
134
  Delete a table and all its data.
126
135
 
127
136
  Args:
137
+ project_id: Project ID (required)
128
138
  table_id: Table ID or table name
129
139
  confirm: Must be True to confirm deletion (safety check)
130
140
 
@@ -132,7 +142,7 @@ class TablesClient:
132
142
  Deletion result with number of rows deleted
133
143
 
134
144
  Example:
135
- >>> result = client.zerodb.tables.delete_table("old_table", confirm=True)
145
+ >>> result = client.zerodb.tables.delete_table(PROJECT_ID, "old_table", confirm=True)
136
146
  >>> print(f"Deleted {result['rows_deleted']} rows")
137
147
  """
138
148
  if not confirm:
@@ -142,12 +152,13 @@ class TablesClient:
142
152
  )
143
153
 
144
154
  data = {"confirm": True}
145
- return self.client.delete(f"{self.base_path}/{table_id}", data=data)
155
+ return self.client.delete(f"{self.base_path}/{project_id}/database/tables/{table_id}", data=data)
146
156
 
147
157
  # Row Operations
148
158
 
149
159
  def insert_rows(
150
160
  self,
161
+ project_id: str,
151
162
  table_name: str,
152
163
  rows: List[Dict[str, Any]],
153
164
  return_ids: bool = True,
@@ -156,6 +167,7 @@ class TablesClient:
156
167
  Insert rows into a table.
157
168
 
158
169
  Args:
170
+ project_id: Project ID (required)
159
171
  table_name: Table name
160
172
  rows: List of row objects to insert (max 1000 per request)
161
173
  return_ids: Whether to return inserted row IDs
@@ -168,7 +180,7 @@ class TablesClient:
168
180
  ... {"email": "user@example.com", "name": "John", "age": 30},
169
181
  ... {"email": "jane@example.com", "name": "Jane", "age": 25}
170
182
  ... ]
171
- >>> result = client.zerodb.tables.insert_rows("users", rows)
183
+ >>> result = client.zerodb.tables.insert_rows(PROJECT_ID, "users", rows)
172
184
  >>> print(f"Inserted {result['inserted_count']} rows")
173
185
  """
174
186
  if not rows:
@@ -182,10 +194,11 @@ class TablesClient:
182
194
  "return_ids": return_ids,
183
195
  }
184
196
 
185
- return self.client.post(f"{self.base_path}/{table_name}/rows", data=data)
197
+ return self.client.post(f"{self.base_path}/{project_id}/database/tables/{table_name}/rows", data=data)
186
198
 
187
199
  def query_rows(
188
200
  self,
201
+ project_id: str,
189
202
  table_name: str,
190
203
  filter: Optional[Dict[str, Any]] = None,
191
204
  sort: Optional[Dict[str, int]] = None,
@@ -197,6 +210,7 @@ class TablesClient:
197
210
  Query rows from a table with filters and sorting.
198
211
 
199
212
  Args:
213
+ project_id: Project ID (required)
200
214
  table_name: Table name
201
215
  filter: MongoDB-style query filter
202
216
  Example: {"age": {"$gte": 25}, "status": "active"}
@@ -213,6 +227,7 @@ class TablesClient:
213
227
  Example:
214
228
  >>> # Query users over 25, sorted by age descending
215
229
  >>> results = client.zerodb.tables.query_rows(
230
+ ... PROJECT_ID,
216
231
  ... "users",
217
232
  ... filter={"age": {"$gte": 25}},
218
233
  ... sort={"age": -1},
@@ -235,10 +250,11 @@ class TablesClient:
235
250
  if projection:
236
251
  data["projection"] = projection
237
252
 
238
- return self.client.post(f"{self.base_path}/{table_name}/query", data=data)
253
+ return self.client.post(f"{self.base_path}/{project_id}/database/tables/{table_name}/query", data=data)
239
254
 
240
255
  def update_rows(
241
256
  self,
257
+ project_id: str,
242
258
  table_name: str,
243
259
  filter: Dict[str, Any],
244
260
  update: Dict[str, Any],
@@ -248,6 +264,7 @@ class TablesClient:
248
264
  Update rows matching the filter.
249
265
 
250
266
  Args:
267
+ project_id: Project ID (required)
251
268
  table_name: Table name
252
269
  filter: MongoDB-style query filter to match rows
253
270
  update: Update operations
@@ -260,6 +277,7 @@ class TablesClient:
260
277
  Example:
261
278
  >>> # Update age for specific user
262
279
  >>> result = client.zerodb.tables.update_rows(
280
+ ... PROJECT_ID,
263
281
  ... "users",
264
282
  ... filter={"email": "user@example.com"},
265
283
  ... update={"$set": {"age": 31}}
@@ -272,10 +290,11 @@ class TablesClient:
272
290
  "upsert": upsert,
273
291
  }
274
292
 
275
- return self.client.put(f"{self.base_path}/{table_name}/rows", data=data)
293
+ return self.client.put(f"{self.base_path}/{project_id}/database/tables/{table_name}/rows", data=data)
276
294
 
277
295
  def delete_rows(
278
296
  self,
297
+ project_id: str,
279
298
  table_name: str,
280
299
  filter: Dict[str, Any],
281
300
  limit: int = 0,
@@ -284,6 +303,7 @@ class TablesClient:
284
303
  Delete rows matching the filter.
285
304
 
286
305
  Args:
306
+ project_id: Project ID (required)
287
307
  table_name: Table name
288
308
  filter: MongoDB-style query filter to match rows
289
309
  limit: Maximum rows to delete (0 = all matching, default)
@@ -294,6 +314,7 @@ class TablesClient:
294
314
  Example:
295
315
  >>> # Delete inactive users
296
316
  >>> result = client.zerodb.tables.delete_rows(
317
+ ... PROJECT_ID,
297
318
  ... "users",
298
319
  ... filter={"age": {"$lt": 18}}
299
320
  ... )
@@ -306,7 +327,7 @@ class TablesClient:
306
327
 
307
328
  return self.client.request(
308
329
  "DELETE",
309
- f"{self.base_path}/{table_name}/rows",
330
+ f"{self.base_path}/{project_id}/database/tables/{table_name}/rows",
310
331
  data=data
311
332
  )
312
333
 
@@ -314,6 +335,7 @@ class TablesClient:
314
335
 
315
336
  def count_rows(
316
337
  self,
338
+ project_id: str,
317
339
  table_name: str,
318
340
  filter: Optional[Dict[str, Any]] = None,
319
341
  ) -> int:
@@ -321,6 +343,7 @@ class TablesClient:
321
343
  Count rows in a table matching optional filter.
322
344
 
323
345
  Args:
346
+ project_id: Project ID (required)
324
347
  table_name: Table name
325
348
  filter: Optional query filter
326
349
 
@@ -328,10 +351,11 @@ class TablesClient:
328
351
  Number of matching rows
329
352
 
330
353
  Example:
331
- >>> count = client.zerodb.tables.count_rows("users", {"age": {"$gte": 18}})
354
+ >>> count = client.zerodb.tables.count_rows(PROJECT_ID, "users", {"age": {"$gte": 18}})
332
355
  >>> print(f"Adult users: {count}")
333
356
  """
334
357
  result = self.query_rows(
358
+ project_id,
335
359
  table_name,
336
360
  filter=filter,
337
361
  limit=0 # Don't return actual rows, just count
@@ -340,23 +364,25 @@ class TablesClient:
340
364
 
341
365
  def table_exists(
342
366
  self,
367
+ project_id: str,
343
368
  table_name: str,
344
369
  ) -> bool:
345
370
  """
346
371
  Check if a table exists.
347
372
 
348
373
  Args:
374
+ project_id: Project ID (required)
349
375
  table_name: Table name to check
350
376
 
351
377
  Returns:
352
378
  True if table exists, False otherwise
353
379
 
354
380
  Example:
355
- >>> if client.zerodb.tables.table_exists("users"):
381
+ >>> if client.zerodb.tables.table_exists(PROJECT_ID, "users"):
356
382
  ... print("Users table exists")
357
383
  """
358
384
  try:
359
- self.get_table(table_name)
385
+ self.get_table(project_id, table_name)
360
386
  return True
361
387
  except Exception:
362
388
  return False
@@ -17,12 +17,13 @@ class VectorsClient:
17
17
  def __init__(self, client: "AINativeClient"):
18
18
  """
19
19
  Initialize vectors client.
20
-
20
+
21
21
  Args:
22
22
  client: Parent AINative client instance
23
23
  """
24
24
  self.client = client
25
- self.base_path = "/zerodb/vectors"
25
+ # Vectors are accessed via /projects/{project_id}/database/vectors/*
26
+ self.base_path = "/projects"
26
27
 
27
28
  def upsert(
28
29
  self,
@@ -66,8 +67,8 @@ class VectorsClient:
66
67
  "namespace": namespace,
67
68
  "items": vector_data,
68
69
  }
69
-
70
- return self.client.put(self.base_path, data=data)
70
+
71
+ return self.client.put(f"{self.base_path}/{project_id}/database/vectors", data=data)
71
72
 
72
73
  def search(
73
74
  self,
@@ -108,8 +109,8 @@ class VectorsClient:
108
109
 
109
110
  if filter:
110
111
  data["filter"] = filter
111
-
112
- response = self.client.post(f"{self.base_path}/search", data=data)
112
+
113
+ response = self.client.post(f"{self.base_path}/{project_id}/database/vectors/search", data=data)
113
114
  return response.get("results", [])
114
115
 
115
116
  def get(
@@ -140,8 +141,8 @@ class VectorsClient:
140
141
  "include_metadata": include_metadata,
141
142
  "include_values": include_values,
142
143
  }
143
-
144
- response = self.client.get(self.base_path, params=params)
144
+
145
+ response = self.client.get(f"{self.base_path}/{project_id}/database/vectors", params=params)
145
146
  return response.get("vectors", [])
146
147
 
147
148
  def delete(
@@ -178,8 +179,8 @@ class VectorsClient:
178
179
  data["filter"] = filter
179
180
  else:
180
181
  raise ValueError("Must provide ids, filter, or delete_all=True")
181
-
182
- return self.client.delete(self.base_path, data=data)
182
+
183
+ return self.client.delete(f"{self.base_path}/{project_id}/database/vectors", data=data)
183
184
 
184
185
  def update_metadata(
185
186
  self,
@@ -206,8 +207,8 @@ class VectorsClient:
206
207
  "metadata": metadata,
207
208
  "namespace": namespace,
208
209
  }
209
-
210
- return self.client.patch(f"{self.base_path}/{id}/metadata", data=data)
210
+
211
+ return self.client.patch(f"{self.base_path}/{project_id}/database/vectors/{id}/metadata", data=data)
211
212
 
212
213
  def describe_index_stats(
213
214
  self,
@@ -227,5 +228,5 @@ class VectorsClient:
227
228
  params = {"project_id": project_id}
228
229
  if namespace:
229
230
  params["namespace"] = namespace
230
-
231
- return self.client.get(f"{self.base_path}/stats", params=params)
231
+
232
+ return self.client.get(f"{self.base_path}/{project_id}/database/vectors/stats", params=params)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ainative-python
3
- Version: 2.0.0
3
+ Version: 3.1.0
4
4
  Summary: Official Python SDK for AINative Studio APIs with ZeroDB Local support
5
5
  Home-page: https://github.com/ainative/ainative-python
6
6
  Author: AINative Team
@@ -26,12 +26,13 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
26
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
27
  Requires-Python: >=3.8
28
28
  Description-Content-Type: text/markdown
29
- Requires-Dist: requests>=2.25.0
30
- Requires-Dist: python-dateutil>=2.8.0
31
- Requires-Dist: typing-extensions>=4.0.0
32
- Requires-Dist: pydantic>=2.0.0
29
+ Requires-Dist: requests>=2.31.0
33
30
  Requires-Dist: httpx>=0.24.0
31
+ Requires-Dist: pydantic>=2.0.0
32
+ Requires-Dist: python-dateutil>=2.8.0
33
+ Requires-Dist: typing-extensions>=4.7.0
34
34
  Requires-Dist: aiohttp>=3.8.0
35
+ Requires-Dist: asyncio>=3.4.3
35
36
  Requires-Dist: numpy>=1.24.0
36
37
  Requires-Dist: PyYAML>=6.0.0
37
38
  Requires-Dist: python-dotenv>=1.0.0
@@ -1,10 +1,10 @@
1
- ainative/__init__.py,sha256=HZ60wi5-m6Lv9GjTkNETKEWahqnDm2npsJk9ROs6xrU,1122
1
+ ainative/__init__.py,sha256=7ABt62Tyhh7-WsGH5FQRj_5BWj1tl8YZ3cv3MRLKKiE,1329
2
2
  ainative/agent_coordination.py,sha256=PGGfQV6C0BIECjJOU1YwU9iaUxbPNazJGAWxNsnJu6k,6557
3
3
  ainative/agent_identity_system.py,sha256=PKlAjwH2nnAbA6m8k2gFAVlCN399aPnqjejthnw7y_c,61331
4
4
  ainative/agent_learning.py,sha256=-_gWl-tqfjRPWFqYG6hYR-dTMucOJfBGyuems-JnBsE,6258
5
5
  ainative/agent_orchestration.py,sha256=Pvip-zN_ArhGEwX07w5uCcYQ0CKDsNfoMAl4UMHd3rM,5277
6
6
  ainative/agent_state.py,sha256=SWrX6evhElWq2n9yFKk9dAMsVwQBS24FjQOgxkT0Vnc,5649
7
- ainative/auth.py,sha256=GjTOzCim-d_eNxegd4bU1lounvs2AmJs4Hpg59X1cmo,3646
7
+ ainative/auth.py,sha256=haBRePZ4YBusxnkrZlWbv7tYve2tAiqEN2MTs2Cldw4,3646
8
8
  ainative/cli.py,sha256=TclB5StZtNME1on8M9PwcU38vI1uTs7xuWi4X44CrR8,20154
9
9
  ainative/client.py,sha256=_vIcCoSmkTUEmyJe87cXPN_3dP0D7O9LAUrf0zpiwn0,9422
10
10
  ainative/exceptions.py,sha256=AUkBQqN_dRF6PGKEkYGUP_g4thVqjWctLy1aNCBDX10,2522
@@ -23,13 +23,13 @@ ainative/commands/swarm.py,sha256=0x98mj0hFUJyTNExEFiz09BcDHzqWUGoGMwaIc0jkFc,55
23
23
  ainative/commands/sync.py,sha256=fVTQToiJdhBjC-6HIH_c5ouYP0IiTlp85-MKiJSD14s,4084
24
24
  ainative/commands/tasks.py,sha256=-xkURYK2bRwndxN9AupmQWMroqLN2mCitJ-Q1vq62bA,5926
25
25
  ainative/zerodb/__init__.py,sha256=LaIU0PDN7epgjEOfJMFKQI6L5aJPipzVwJG3MR14NXA,2531
26
- ainative/zerodb/analytics.py,sha256=dcxUY19_-o_SNWFHr6oxOub7g4JdWaORDGkNuQVX3XQ,6623
27
- ainative/zerodb/memory.py,sha256=-cbqSCU53DBRgbbgpz72nStnqqh0m0xT5N7KgAERff0,7202
28
- ainative/zerodb/projects.py,sha256=663LD_gCXnlGX0sZsUg-kBy5j9tpOmCbyo4wBT1U__Y,6021
29
- ainative/zerodb/tables.py,sha256=5y6Pd0pR_8aYpE1rZnyOKb56xdytizlteYWJlzWW3EA,10198
30
- ainative/zerodb/vectors.py,sha256=kiaa39bNMqUMmJDaPOG2tT_y3O2t7uEnxfTTn3KrlU0,6497
31
- ainative_python-2.0.0.dist-info/METADATA,sha256=DUcBbgC5nTPPl9XAju8gl9mTAr5bBA74lQBMsmMs2yo,13362
32
- ainative_python-2.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
- ainative_python-2.0.0.dist-info/entry_points.txt,sha256=IMzkHrb-9Xmehjqb99G4j5avDvvD0acsKvDjLByiKLo,47
34
- ainative_python-2.0.0.dist-info/top_level.txt,sha256=ykLnDIPJjvN3FV9QlyqCePGbglJvhZPft1xprQ0uo9A,9
35
- ainative_python-2.0.0.dist-info/RECORD,,
26
+ ainative/zerodb/analytics.py,sha256=fXgO7NHmdgo1bS4NCUOvU-7Ds-U57aZmIm2XmUBJSRw,5926
27
+ ainative/zerodb/memory.py,sha256=xbhLBP5GlaYHxnzyf2cY5cDqAOC7DbmFo5SKjYri-5c,7667
28
+ ainative/zerodb/projects.py,sha256=iNnsLVuionQF2ueLgXYxNvF1dChpPHoTrMdjVOnWnZA,6006
29
+ ainative/zerodb/tables.py,sha256=luxQvnQZieF8GNVWUEpf9VUpj4em2k7deIV2Ul4Zfbw,11456
30
+ ainative/zerodb/vectors.py,sha256=uG2-S2K7ToTfeJ_D3enGoieey4yK6yNF3_ZSNWVr7Ik,6707
31
+ ainative_python-3.1.0.dist-info/METADATA,sha256=ny97XJZZ_mDbVVz4oAt0UYGn0Naihd2Ux4FqWZILLc4,13392
32
+ ainative_python-3.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ ainative_python-3.1.0.dist-info/entry_points.txt,sha256=IMzkHrb-9Xmehjqb99G4j5avDvvD0acsKvDjLByiKLo,47
34
+ ainative_python-3.1.0.dist-info/top_level.txt,sha256=ykLnDIPJjvN3FV9QlyqCePGbglJvhZPft1xprQ0uo9A,9
35
+ ainative_python-3.1.0.dist-info/RECORD,,