proxima-sdk 1.0.0__tar.gz

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,35 @@
1
+ # Synthetic data (generated, ~1.3GB)
2
+ agents/supply-chain/demand-forecasting/data/synthetic/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.pyc
7
+ *.pyo
8
+ .venv/
9
+ venv/
10
+ env/
11
+ *.egg-info/
12
+
13
+ # Environment
14
+ .env
15
+ .env.local
16
+
17
+ # IDE
18
+ .vscode/
19
+ .idea/
20
+ *.swp
21
+
22
+ # OS
23
+ .DS_Store
24
+ Thumbs.db
25
+
26
+ # Original reference docs (large PDFs, keep .md conversions only)
27
+ docs/reference/daimler/*.pdf
28
+ docs/reference/daimler/*.pptx
29
+ docs/reference/daimler/*.docx
30
+ docs/reference/daimler/*.msg
31
+ docs/reference/daimler/*.xlsx
32
+ docs/reference/daimler/*.zip
33
+ docs/reference/daimler/SAP Proposal - Supply Chain RFP/*.pdf
34
+ docs/reference/daimler/SAP Proposal - Supply Chain RFP/*.xlsx
35
+ platform/data/secrets.json
@@ -0,0 +1,57 @@
1
+ Metadata-Version: 2.4
2
+ Name: proxima-sdk
3
+ Version: 1.0.0
4
+ Summary: Proxima AIP SDK — build AI agents on the Proxima Intelligence platform
5
+ Project-URL: Homepage, https://proximaintel.com/aip
6
+ Project-URL: Documentation, https://docs.proximaintel.com/sdk
7
+ Project-URL: Repository, https://github.com/proximaintel/proxima-sdk
8
+ Author-email: Proxima Intelligence <hello@proximaintel.com>
9
+ License-Expression: MIT
10
+ Keywords: agents,ai,enterprise,platform,proxima
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Python: >=3.11
17
+ Requires-Dist: httpx>=0.27
18
+ Requires-Dist: pydantic>=2.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # Proxima SDK
22
+
23
+ The official Python SDK for building AI agents on the **Proxima AIP** platform.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install proxima-sdk
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```python
34
+ from proxima_sdk import PlatformContext
35
+
36
+ def my_tool(params: dict, ctx: PlatformContext) -> dict:
37
+ # Access knowledge bases
38
+ data = ctx.knowledge.query("What invoices are overdue?")
39
+
40
+ # Log actions for governance
41
+ ctx.governance.log_action("queried_invoices")
42
+
43
+ return {"answer": data.answer, "citations": data.citations}
44
+ ```
45
+
46
+ ## Testing
47
+
48
+ ```python
49
+ from proxima_sdk.testing import mock_context
50
+
51
+ ctx = mock_context(sources={"invoices": [{"id": "INV-001", "amount": 5000}]})
52
+ result = my_tool({"query": "overdue"}, ctx)
53
+ ```
54
+
55
+ ## Documentation
56
+
57
+ Full docs at [docs.proximaintel.com/sdk](https://docs.proximaintel.com/sdk)
@@ -0,0 +1,37 @@
1
+ # Proxima SDK
2
+
3
+ The official Python SDK for building AI agents on the **Proxima AIP** platform.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install proxima-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from proxima_sdk import PlatformContext
15
+
16
+ def my_tool(params: dict, ctx: PlatformContext) -> dict:
17
+ # Access knowledge bases
18
+ data = ctx.knowledge.query("What invoices are overdue?")
19
+
20
+ # Log actions for governance
21
+ ctx.governance.log_action("queried_invoices")
22
+
23
+ return {"answer": data.answer, "citations": data.citations}
24
+ ```
25
+
26
+ ## Testing
27
+
28
+ ```python
29
+ from proxima_sdk.testing import mock_context
30
+
31
+ ctx = mock_context(sources={"invoices": [{"id": "INV-001", "amount": 5000}]})
32
+ result = my_tool({"query": "overdue"}, ctx)
33
+ ```
34
+
35
+ ## Documentation
36
+
37
+ Full docs at [docs.proximaintel.com/sdk](https://docs.proximaintel.com/sdk)
@@ -0,0 +1,50 @@
1
+ """
2
+ Proxima SDK
3
+
4
+ The official SDK for building toolboxes on the Proxima Intelligence platform.
5
+ Provides typed access to Knowledge, Governance, and Secrets services.
6
+
7
+ Quick Start:
8
+ from proxima_sdk import PlatformContext
9
+
10
+ def my_tool(params: dict, ctx: PlatformContext) -> dict:
11
+ data = ctx.knowledge.read("invoices-gold")
12
+ ctx.governance.log_action("processed_invoice")
13
+ return {"count": len(data)}
14
+
15
+ Testing:
16
+ from proxima_sdk.testing import mock_context
17
+ import pandas as pd
18
+
19
+ ctx = mock_context(sources={"invoices-gold": pd.DataFrame([...])})
20
+ result = my_tool({"id": "INV-001"}, ctx)
21
+ """
22
+
23
+ from .context import PlatformContext
24
+ from .knowledge import KnowledgeClient
25
+ from .exceptions import (
26
+ ProximaError,
27
+ SourceNotFoundError,
28
+ ConnectionFailedError,
29
+ QueryFailedError,
30
+ SecretNotFoundError,
31
+ PermissionDeniedError,
32
+ )
33
+ from .types import SearchResult, SearchResults, Citation, QueryMetadata
34
+
35
+ __version__ = "1.0.0"
36
+
37
+ __all__ = [
38
+ "PlatformContext",
39
+ "KnowledgeClient",
40
+ "ProximaError",
41
+ "SourceNotFoundError",
42
+ "ConnectionFailedError",
43
+ "QueryFailedError",
44
+ "SecretNotFoundError",
45
+ "PermissionDeniedError",
46
+ "SearchResult",
47
+ "SearchResults",
48
+ "Citation",
49
+ "QueryMetadata",
50
+ ]
@@ -0,0 +1,140 @@
1
+ """
2
+ Proxima SDK — Platform Context
3
+
4
+ The single entry point injected into every toolbox tool call.
5
+ Contains everything the toolbox needs to interact with the platform.
6
+
7
+ Usage:
8
+ from proxima_sdk import PlatformContext
9
+
10
+ def my_tool(params: dict, ctx: PlatformContext) -> dict:
11
+ data = ctx.knowledge.read("invoices-gold")
12
+ ctx.governance.log_action("validated_invoice", {"id": params["invoice_id"]})
13
+ return {"result": "pass"}
14
+ """
15
+
16
+ from typing import Optional
17
+ from .knowledge import KnowledgeClient
18
+
19
+
20
+ class GovernanceClient:
21
+ """Log actions and events to the platform governance system."""
22
+
23
+ def __init__(self, gateway_url: str, agent_id: str):
24
+ self._gateway_url = gateway_url
25
+ self._agent_id = agent_id
26
+
27
+ def log_action(self, action: str, detail: dict | None = None):
28
+ """Log a toolbox action to governance (async fire-and-forget)."""
29
+ import httpx
30
+ try:
31
+ httpx.post(
32
+ f"{self._gateway_url}/governance/logs",
33
+ json={"agent_id": self._agent_id, "type": "action", "action": action, "detail": detail or {}},
34
+ timeout=5.0,
35
+ )
36
+ except Exception:
37
+ pass # Non-blocking — governance logging should never break tool execution
38
+
39
+
40
+ class SecretsClient:
41
+ """Resolve secrets from the platform secret store."""
42
+
43
+ def __init__(self, gateway_url: str):
44
+ self._gateway_url = gateway_url
45
+
46
+ def resolve(self, name: str) -> str:
47
+ """Resolve a secret value by name."""
48
+ import httpx
49
+ from .exceptions import SecretNotFoundError, ConnectionFailedError
50
+ try:
51
+ res = httpx.post(f"{self._gateway_url}/internal/secrets/resolve", json={"name": name}, timeout=5.0)
52
+ if res.status_code == 200:
53
+ return res.json().get("value", "")
54
+ elif res.status_code == 404:
55
+ raise SecretNotFoundError(name)
56
+ return ""
57
+ except httpx.ConnectError:
58
+ raise ConnectionFailedError("Gateway", self._gateway_url)
59
+
60
+
61
+ class PlatformContext:
62
+ """
63
+ Injected into every tool call. Provides access to all platform services.
64
+
65
+ Constructed by the gateway from the agent's config and passed to the toolbox
66
+ in the request payload under the `_context` key.
67
+ """
68
+
69
+ def __init__(self, config: dict):
70
+ """
71
+ Args:
72
+ config: The _context dict injected by the gateway into tool call payloads.
73
+ {
74
+ "gateway_url": "https://gateway.example.com",
75
+ "agent_id": "invoice-intelligence",
76
+ "knowledge_bases": ["finance-kb"],
77
+ "sources": [...],
78
+ "token": "<_context HMAC token for dev mode>",
79
+ "identity": {
80
+ "client_id": "<agent SP client_id>",
81
+ "client_secret": "<agent SP secret>",
82
+ "tenant_id": "<IdP tenant>",
83
+ "audience": "api://<gateway app id>"
84
+ }
85
+ }
86
+ """
87
+ self._config = config
88
+ self._knowledge: Optional[KnowledgeClient] = None
89
+ self._governance: Optional[GovernanceClient] = None
90
+ self._secrets: Optional[SecretsClient] = None
91
+
92
+ @property
93
+ def knowledge(self) -> KnowledgeClient:
94
+ """Access enterprise data through the gateway."""
95
+ if self._knowledge is None:
96
+ identity = self._config.get("identity", {})
97
+ self._knowledge = KnowledgeClient(
98
+ gateway_url=self._config.get("gateway_url", "http://localhost:9000"),
99
+ knowledge_bases=self._config.get("knowledge_bases", []),
100
+ sources=self._config.get("sources", []),
101
+ token=self._config.get("token", ""),
102
+ client_id=identity.get("client_id", ""),
103
+ client_secret=identity.get("client_secret", ""),
104
+ tenant_id=identity.get("tenant_id", ""),
105
+ audience=identity.get("audience", ""),
106
+ )
107
+ return self._knowledge
108
+
109
+ @property
110
+ def governance(self) -> GovernanceClient:
111
+ """Log actions to the platform governance system."""
112
+ if self._governance is None:
113
+ self._governance = GovernanceClient(
114
+ gateway_url=self._config.get("gateway_url", "http://localhost:9000"),
115
+ agent_id=self._config.get("agent_id", ""),
116
+ )
117
+ return self._governance
118
+
119
+ @property
120
+ def secrets(self) -> SecretsClient:
121
+ """Resolve secrets from the platform secret store."""
122
+ if self._secrets is None:
123
+ self._secrets = SecretsClient(
124
+ gateway_url=self._config.get("gateway_url", "http://localhost:9000"),
125
+ )
126
+ return self._secrets
127
+
128
+ @property
129
+ def agent_id(self) -> str:
130
+ return self._config.get("agent_id", "")
131
+
132
+ def close(self):
133
+ if self._knowledge:
134
+ self._knowledge.close()
135
+
136
+ def __enter__(self):
137
+ return self
138
+
139
+ def __exit__(self, *args):
140
+ self.close()
@@ -0,0 +1,55 @@
1
+ """
2
+ Proxima SDK — Exceptions
3
+
4
+ Clear, typed exceptions for toolbox developers.
5
+ Every error tells you what went wrong and how to fix it.
6
+ """
7
+
8
+
9
+ class ProximaError(Exception):
10
+ """Base exception for all Proxima SDK errors."""
11
+ pass
12
+
13
+
14
+ class SourceNotFoundError(ProximaError):
15
+ """Knowledge source not found in the connected knowledge base."""
16
+ def __init__(self, source_id: str):
17
+ super().__init__(f"Knowledge source '{source_id}' not found. Check that the source is registered and connected to the agent's knowledge base.")
18
+ self.source_id = source_id
19
+
20
+
21
+ class ConnectionFailedError(ProximaError):
22
+ """Failed to connect to a platform service (Knowledge Service, Gateway)."""
23
+ def __init__(self, service: str, url: str, detail: str = ""):
24
+ super().__init__(f"Failed to connect to {service} at {url}. {detail}")
25
+ self.service = service
26
+ self.url = url
27
+
28
+
29
+ class QueryFailedError(ProximaError):
30
+ """Knowledge query failed — source unreachable or credentials invalid."""
31
+ def __init__(self, source_id: str, detail: str = ""):
32
+ super().__init__(f"Query failed for source '{source_id}'. {detail}")
33
+ self.source_id = source_id
34
+
35
+
36
+ class SecretNotFoundError(ProximaError):
37
+ """Secret not found in the platform secret store."""
38
+ def __init__(self, secret_name: str):
39
+ super().__init__(f"Secret '{secret_name}' not found in platform secret store.")
40
+ self.secret_name = secret_name
41
+
42
+
43
+ class PermissionDeniedError(ProximaError):
44
+ """Insufficient permissions for the requested operation."""
45
+ def __init__(self, operation: str, detail: str = ""):
46
+ super().__init__(f"Permission denied for '{operation}'. {detail}")
47
+ self.operation = operation
48
+
49
+
50
+ class TimeoutError(ProximaError):
51
+ """Request timed out."""
52
+ def __init__(self, service: str, timeout_seconds: float):
53
+ super().__init__(f"Request to {service} timed out after {timeout_seconds}s.")
54
+ self.service = service
55
+ self.timeout_seconds = timeout_seconds
@@ -0,0 +1,269 @@
1
+ """
2
+ Proxima SDK — Knowledge Client
3
+
4
+ The primary interface for toolboxes to access enterprise data.
5
+ All access goes through the gateway (authenticated, RBAC-enforced, governance-logged).
6
+
7
+ The toolbox NEVER calls Knowledge Service directly. It authenticates to the gateway
8
+ using the agent's service principal credentials and calls POST /knowledge/{base_id}/query.
9
+
10
+ Usage:
11
+ from proxima_sdk import PlatformContext
12
+
13
+ def validate_invoice(params: dict, ctx: PlatformContext) -> dict:
14
+ results = ctx.knowledge.query("finance-kb", "overdue invoices over $50K")
15
+ invoices = ctx.knowledge.read("invoices-gold")
16
+ # ... business logic
17
+ """
18
+
19
+ import os
20
+ import time
21
+ from typing import Optional
22
+
23
+ import httpx
24
+ import pandas as pd
25
+
26
+ from .types import SearchResult, SearchResults, Citation, QueryMetadata
27
+ from .exceptions import (
28
+ SourceNotFoundError,
29
+ ConnectionFailedError,
30
+ QueryFailedError,
31
+ TimeoutError as ProximaTimeoutError,
32
+ )
33
+
34
+
35
+ class KnowledgeClient:
36
+ """
37
+ Access enterprise data through the Proxima Gateway.
38
+
39
+ Provides:
40
+ - query(base_id, query) → dict (full KB query via gateway)
41
+ - read(source_id) → pd.DataFrame (structured data via gateway)
42
+ - search(source_id, query) → SearchResults (unstructured/vector via gateway)
43
+
44
+ All access authenticated, RBAC-enforced, governance-logged.
45
+ """
46
+
47
+ def __init__(self, gateway_url: str, knowledge_bases: list[str], sources: list[dict],
48
+ token: str = "", client_id: str = "", client_secret: str = "",
49
+ tenant_id: str = "", audience: str = "", timeout: float = 30.0):
50
+ """
51
+ Args:
52
+ gateway_url: Platform gateway URL (e.g., https://gateway.example.com)
53
+ knowledge_bases: List of KB IDs this agent can access
54
+ sources: Legacy source definitions (for backward compat with read())
55
+ token: Pre-obtained token (dev mode / _context HMAC)
56
+ client_id: Agent SP client ID (production - client credentials flow)
57
+ client_secret: Agent SP client secret (production)
58
+ tenant_id: IdP tenant ID (for token endpoint)
59
+ audience: Gateway audience (for token scope)
60
+ timeout: HTTP timeout in seconds
61
+ """
62
+ self._gateway_url = gateway_url.rstrip("/")
63
+ self._knowledge_bases = knowledge_bases
64
+ self._sources = {s["id"]: s for s in sources}
65
+ self._timeout = timeout
66
+ self._cache: dict[str, pd.DataFrame] = {}
67
+
68
+ # Auth
69
+ self._token = token
70
+ self._client_id = client_id or os.getenv("PROXIMA_AGENT_CLIENT_ID", "")
71
+ self._client_secret = client_secret or os.getenv("PROXIMA_AGENT_CLIENT_SECRET", "")
72
+ self._tenant_id = tenant_id or os.getenv("PROXIMA_TENANT_ID", "")
73
+ self._audience = audience or os.getenv("PROXIMA_AUDIENCE", "")
74
+ self._token_expires_at: float = 0
75
+
76
+ def _get_token(self) -> str:
77
+ """Get a valid access token. Uses cached token if not expired."""
78
+ # If we have a pre-set token (dev mode / _context), use it
79
+ if self._token and not self._client_id:
80
+ return self._token
81
+
82
+ # Check if cached token is still valid (with 60s buffer)
83
+ if self._token and time.time() < self._token_expires_at - 60:
84
+ return self._token
85
+
86
+ # Client credentials flow
87
+ if not self._client_id or not self._client_secret or not self._tenant_id:
88
+ return self._token # Fall back to whatever we have
89
+
90
+ token_url = f"https://login.microsoftonline.com/{self._tenant_id}/oauth2/v2.0/token"
91
+ scope = f"{self._audience}/.default" if self._audience else ""
92
+
93
+ try:
94
+ res = httpx.post(token_url, data={
95
+ "client_id": self._client_id,
96
+ "client_secret": self._client_secret,
97
+ "scope": scope,
98
+ "grant_type": "client_credentials",
99
+ }, timeout=10.0)
100
+
101
+ if res.status_code == 200:
102
+ data = res.json()
103
+ self._token = data["access_token"]
104
+ self._token_expires_at = time.time() + data.get("expires_in", 3600)
105
+ return self._token
106
+ except Exception:
107
+ pass
108
+
109
+ return self._token
110
+
111
+ def _headers(self) -> dict:
112
+ """Build request headers with auth token."""
113
+ token = self._get_token()
114
+ headers = {"Content-Type": "application/json"}
115
+ if token:
116
+ headers["Authorization"] = f"Bearer {token}"
117
+ return headers
118
+
119
+ def query(self, base_id: str, query: str, top_k: int = 5) -> dict:
120
+ """
121
+ Query a knowledge base through the gateway.
122
+
123
+ Args:
124
+ base_id: Knowledge base ID
125
+ query: Natural language query
126
+ top_k: Number of results
127
+
128
+ Returns:
129
+ dict with results, citations, metadata
130
+
131
+ Raises:
132
+ QueryFailedError: Gateway returned an error
133
+ ConnectionFailedError: Gateway unreachable
134
+ """
135
+ try:
136
+ start = time.time()
137
+ res = httpx.post(
138
+ f"{self._gateway_url}/knowledge/{base_id}/query",
139
+ json={"query": query, "top_k": top_k},
140
+ headers=self._headers(),
141
+ timeout=self._timeout,
142
+ )
143
+ duration = int((time.time() - start) * 1000)
144
+
145
+ if res.status_code == 403:
146
+ raise QueryFailedError(base_id, "Access denied. Check role_assignments for this agent.")
147
+ if res.status_code == 404:
148
+ raise SourceNotFoundError(base_id)
149
+ if res.status_code != 200:
150
+ raise QueryFailedError(base_id, f"HTTP {res.status_code}: {res.text[:200]}")
151
+
152
+ return res.json()
153
+
154
+ except httpx.ConnectError:
155
+ raise ConnectionFailedError("Gateway", self._gateway_url, "Gateway unreachable.")
156
+ except httpx.TimeoutException:
157
+ raise ProximaTimeoutError("Gateway", self._timeout)
158
+
159
+ def read(self, source_id: str, use_cache: bool = True) -> pd.DataFrame:
160
+ """
161
+ Read structured data from a knowledge source.
162
+ Routes through gateway /knowledge/{base_id}/query.
163
+
164
+ Args:
165
+ source_id: ID of the registered knowledge source
166
+ use_cache: If True, returns cached data within same tool execution
167
+
168
+ Returns:
169
+ pd.DataFrame with the source data
170
+ """
171
+ if use_cache and source_id in self._cache:
172
+ return self._cache[source_id]
173
+
174
+ # Find which KB contains this source
175
+ # For now, query the first available KB with the source name
176
+ base_id = self._knowledge_bases[0] if self._knowledge_bases else "default"
177
+
178
+ result = self.query(base_id, f"read all data from {source_id}", top_k=1)
179
+
180
+ # Parse results into DataFrame
181
+ for r in result.get("results", []):
182
+ content = r.get("content", "")
183
+ if "rows" in content and "|" in content:
184
+ # Try to parse markdown table
185
+ try:
186
+ lines = [l.strip() for l in content.split("\n") if l.strip() and "|" in l]
187
+ if len(lines) >= 3:
188
+ headers = [h.strip() for h in lines[0].split("|") if h.strip()]
189
+ rows = []
190
+ for line in lines[2:]:
191
+ if "---" in line or "..." in line:
192
+ continue
193
+ row = [c.strip() for c in line.split("|") if c.strip()]
194
+ if len(row) == len(headers):
195
+ rows.append(row)
196
+ if rows:
197
+ df = pd.DataFrame(rows, columns=headers)
198
+ if use_cache:
199
+ self._cache[source_id] = df
200
+ return df
201
+ except Exception:
202
+ pass
203
+
204
+ # Fallback: return empty DataFrame
205
+ df = pd.DataFrame()
206
+ if use_cache:
207
+ self._cache[source_id] = df
208
+ return df
209
+
210
+ def search(self, source_id: str, query: str, top_k: int = 5) -> SearchResults:
211
+ """
212
+ Search knowledge via gateway.
213
+
214
+ Args:
215
+ source_id: Source or KB ID to search
216
+ query: Natural language search query
217
+ top_k: Number of results
218
+
219
+ Returns:
220
+ SearchResults with content and citations
221
+ """
222
+ base_id = source_id if source_id in self._knowledge_bases else (self._knowledge_bases[0] if self._knowledge_bases else source_id)
223
+
224
+ result = self.query(base_id, query, top_k=top_k)
225
+
226
+ results = []
227
+ for r in result.get("results", []):
228
+ citation_data = r.get("citation", {})
229
+ results.append(SearchResult(
230
+ content=r.get("content", ""),
231
+ citation=Citation(
232
+ source=citation_data.get("source", ""),
233
+ title=citation_data.get("title", ""),
234
+ confidence=citation_data.get("confidence", 0.0),
235
+ metadata=citation_data,
236
+ ),
237
+ score=0.0,
238
+ ))
239
+
240
+ return SearchResults(
241
+ results=results,
242
+ query=query,
243
+ sources_queried=result.get("metadata", {}).get("sources_queried", 0),
244
+ duration_ms=result.get("metadata", {}).get("duration_ms", 0),
245
+ )
246
+
247
+ @property
248
+ def available_bases(self) -> list[str]:
249
+ """List KB IDs available to this agent."""
250
+ return list(self._knowledge_bases)
251
+
252
+ @property
253
+ def available_sources(self) -> list[str]:
254
+ """List source IDs (legacy compat)."""
255
+ return list(self._sources.keys())
256
+
257
+ def clear_cache(self):
258
+ """Clear the in-memory read cache."""
259
+ self._cache.clear()
260
+
261
+ def close(self):
262
+ """No persistent client to close (stateless HTTP calls)."""
263
+ pass
264
+
265
+ def __enter__(self):
266
+ return self
267
+
268
+ def __exit__(self, *args):
269
+ self.close()
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "proxima-sdk"
7
+ version = "1.0.0"
8
+ description = "Proxima AIP SDK — build AI agents on the Proxima Intelligence platform"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "Proxima Intelligence", email = "hello@proximaintel.com" },
14
+ ]
15
+ keywords = ["ai", "agents", "platform", "enterprise", "proxima"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ ]
23
+ dependencies = [
24
+ "httpx>=0.27",
25
+ "pydantic>=2.0",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://proximaintel.com/aip"
30
+ Documentation = "https://docs.proximaintel.com/sdk"
31
+ Repository = "https://github.com/proximaintel/proxima-sdk"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["proxima_sdk"]
@@ -0,0 +1,90 @@
1
+ """
2
+ Proxima SDK — Testing Utilities
3
+
4
+ Mock clients for unit testing toolbox code without the full platform stack.
5
+
6
+ Usage:
7
+ from proxima_sdk.testing import mock_context
8
+ import pandas as pd
9
+
10
+ def test_validate_invoice():
11
+ ctx = mock_context(sources={
12
+ "invoices-gold": pd.DataFrame([{"invoice_id": "INV-001", "amount": 1000}]),
13
+ "vendors-gold": pd.DataFrame([{"vendor_id": "V-001", "name": "Acme"}]),
14
+ })
15
+ result = validate_invoice({"invoice_id": "INV-001"}, ctx)
16
+ assert result["validation"] == "pass"
17
+ """
18
+
19
+ from typing import Optional
20
+ import pandas as pd
21
+ from .types import SearchResult, SearchResults, Citation
22
+ from .context import PlatformContext
23
+
24
+
25
+ class MockKnowledgeClient:
26
+ """Mock knowledge client for testing. Returns pre-loaded DataFrames."""
27
+
28
+ def __init__(self, sources: dict[str, pd.DataFrame] | None = None, search_results: dict[str, list[dict]] | None = None):
29
+ self._sources = sources or {}
30
+ self._search_results = search_results or {}
31
+
32
+ def read(self, source_id: str, use_cache: bool = True) -> pd.DataFrame:
33
+ if source_id not in self._sources:
34
+ from .exceptions import SourceNotFoundError
35
+ raise SourceNotFoundError(source_id)
36
+ return self._sources[source_id]
37
+
38
+ def search(self, source_id: str, query: str, top_k: int = 5) -> SearchResults:
39
+ results = self._search_results.get(source_id, [])
40
+ return SearchResults(
41
+ results=[SearchResult(content=r.get("content", ""), citation=Citation(source=source_id, title=r.get("title", "")), score=r.get("score", 0.9)) for r in results[:top_k]],
42
+ query=query,
43
+ sources_queried=1,
44
+ duration_ms=1,
45
+ )
46
+
47
+ @property
48
+ def available_sources(self) -> list[str]:
49
+ return list(self._sources.keys())
50
+
51
+ def clear_cache(self):
52
+ pass
53
+
54
+ def close(self):
55
+ pass
56
+
57
+
58
+ class MockGovernanceClient:
59
+ """Mock governance client — records actions for assertion."""
60
+
61
+ def __init__(self):
62
+ self.actions: list[dict] = []
63
+
64
+ def log_action(self, action: str, detail: dict | None = None):
65
+ self.actions.append({"action": action, "detail": detail or {}})
66
+
67
+
68
+ class MockSecretsClient:
69
+ """Mock secrets client — returns pre-configured values."""
70
+
71
+ def __init__(self, secrets: dict[str, str] | None = None):
72
+ self._secrets = secrets or {}
73
+
74
+ def resolve(self, name: str) -> str:
75
+ return self._secrets.get(name, "")
76
+
77
+
78
+ class MockPlatformContext(PlatformContext):
79
+ """Mock platform context for testing."""
80
+
81
+ def __init__(self, sources: dict[str, pd.DataFrame] | None = None, search_results: dict[str, list[dict]] | None = None, secrets: dict[str, str] | None = None):
82
+ super().__init__({"agent_id": "test-agent", "knowledge_service_url": "", "gateway_url": "", "sources": []})
83
+ self._knowledge = MockKnowledgeClient(sources=sources, search_results=search_results)
84
+ self._governance = MockGovernanceClient()
85
+ self._secrets = MockSecretsClient(secrets=secrets)
86
+
87
+
88
+ def mock_context(sources: dict[str, pd.DataFrame] | None = None, search_results: dict[str, list[dict]] | None = None, secrets: dict[str, str] | None = None) -> MockPlatformContext:
89
+ """Create a mock PlatformContext for unit testing."""
90
+ return MockPlatformContext(sources=sources, search_results=search_results, secrets=secrets)
@@ -0,0 +1,62 @@
1
+ """
2
+ Proxima SDK — Types
3
+
4
+ Typed data structures for toolbox developers.
5
+ """
6
+
7
+ from dataclasses import dataclass, field
8
+ from typing import Any, Optional
9
+
10
+
11
+ @dataclass
12
+ class Citation:
13
+ """Source attribution for a knowledge retrieval result."""
14
+ source: str
15
+ title: str = ""
16
+ section: str = ""
17
+ page: Optional[int] = None
18
+ url: str = ""
19
+ confidence: float = 0.0
20
+ metadata: dict = field(default_factory=dict)
21
+
22
+
23
+ @dataclass
24
+ class SearchResult:
25
+ """A single result from a knowledge search (unstructured/vector)."""
26
+ content: str
27
+ citation: Citation
28
+ score: float = 0.0
29
+
30
+
31
+ @dataclass
32
+ class SearchResults:
33
+ """Collection of search results with metadata."""
34
+ results: list[SearchResult]
35
+ query: str
36
+ sources_queried: int = 0
37
+ duration_ms: int = 0
38
+
39
+ def __len__(self) -> int:
40
+ return len(self.results)
41
+
42
+ def __iter__(self):
43
+ return iter(self.results)
44
+
45
+ @property
46
+ def top(self) -> Optional[SearchResult]:
47
+ return self.results[0] if self.results else None
48
+
49
+ @property
50
+ def contents(self) -> list[str]:
51
+ return [r.content for r in self.results]
52
+
53
+
54
+ @dataclass
55
+ class QueryMetadata:
56
+ """Metadata about a structured data query."""
57
+ source: str
58
+ row_count: int
59
+ columns: list[str]
60
+ query_executed: str = ""
61
+ duration_ms: int = 0
62
+ cached: bool = False