casfa-client 0.1.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.
Files changed (36) hide show
  1. casfa_client-0.1.0/PKG-INFO +166 -0
  2. casfa_client-0.1.0/README.md +141 -0
  3. casfa_client-0.1.0/casfa/__init__.py +227 -0
  4. casfa_client-0.1.0/casfa/api/__init__.py +21 -0
  5. casfa_client-0.1.0/casfa/api/admin.py +81 -0
  6. casfa_client-0.1.0/casfa/api/auth.py +230 -0
  7. casfa_client-0.1.0/casfa/api/depots.py +207 -0
  8. casfa_client-0.1.0/casfa/api/mcp.py +90 -0
  9. casfa_client-0.1.0/casfa/api/nodes.py +147 -0
  10. casfa_client-0.1.0/casfa/api/oauth.py +156 -0
  11. casfa_client-0.1.0/casfa/api/realm.py +58 -0
  12. casfa_client-0.1.0/casfa/api/tickets.py +184 -0
  13. casfa_client-0.1.0/casfa/auth/__init__.py +37 -0
  14. casfa_client-0.1.0/casfa/auth/p256.py +177 -0
  15. casfa_client-0.1.0/casfa/auth/permissions.py +158 -0
  16. casfa_client-0.1.0/casfa/auth/ticket.py +95 -0
  17. casfa_client-0.1.0/casfa/auth/token.py +36 -0
  18. casfa_client-0.1.0/casfa/auth/user.py +181 -0
  19. casfa_client-0.1.0/casfa/client.py +191 -0
  20. casfa_client-0.1.0/casfa/types/__init__.py +118 -0
  21. casfa_client-0.1.0/casfa/types/api.py +314 -0
  22. casfa_client-0.1.0/casfa/types/auth.py +160 -0
  23. casfa_client-0.1.0/casfa/types/providers.py +60 -0
  24. casfa_client-0.1.0/casfa/utils/__init__.py +37 -0
  25. casfa_client-0.1.0/casfa/utils/errors.py +83 -0
  26. casfa_client-0.1.0/casfa/utils/fetch.py +259 -0
  27. casfa_client-0.1.0/casfa_client.egg-info/PKG-INFO +166 -0
  28. casfa_client-0.1.0/casfa_client.egg-info/SOURCES.txt +34 -0
  29. casfa_client-0.1.0/casfa_client.egg-info/dependency_links.txt +1 -0
  30. casfa_client-0.1.0/casfa_client.egg-info/requires.txt +10 -0
  31. casfa_client-0.1.0/casfa_client.egg-info/top_level.txt +1 -0
  32. casfa_client-0.1.0/pyproject.toml +53 -0
  33. casfa_client-0.1.0/setup.cfg +4 -0
  34. casfa_client-0.1.0/tests/test_auth.py +180 -0
  35. casfa_client-0.1.0/tests/test_client.py +108 -0
  36. casfa_client-0.1.0/tests/test_types.py +167 -0
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: casfa-client
3
+ Version: 0.1.0
4
+ Summary: CASFA (Content-Addressable Storage for Agents) Python SDK
5
+ Author: Mitsein Team
6
+ License-Expression: MIT
7
+ Keywords: casfa,cas,content-addressable,storage,agents
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Typing :: Typed
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: httpx>=0.27.0
17
+ Requires-Dist: pydantic>=2.0.0
18
+ Requires-Dist: cryptography>=42.0.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
22
+ Requires-Dist: pytest-httpx>=0.30.0; extra == "dev"
23
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
24
+ Requires-Dist: mypy>=1.10.0; extra == "dev"
25
+
26
+ # CASFA Python SDK
27
+
28
+ Python client for CASFA (Content-Addressable Storage for Agents).
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install casfa-client
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ### Agent Token Authentication
39
+
40
+ ```python
41
+ import asyncio
42
+ from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
43
+
44
+ async def main():
45
+ # Create client with agent token
46
+ client = create_casfa_client(CasfaClientConfig(
47
+ base_url="https://casfa.example.com",
48
+ auth=TokenAuthConfig(type="token", token="casfa_xxx"),
49
+ realm_id="user:ABC123",
50
+ ))
51
+
52
+ # Get realm usage
53
+ result = await client.realm.get_usage()
54
+ if result.ok:
55
+ print(f"Nodes: {result.data.node_count}")
56
+ print(f"Bytes: {result.data.total_bytes}")
57
+ else:
58
+ print(f"Error: {result.error.message}")
59
+
60
+ # List depots
61
+ result = await client.depots.list()
62
+ if result.ok:
63
+ for depot in result.data.items:
64
+ print(f"Depot: {depot.title} (v{depot.version})")
65
+
66
+ await client.close()
67
+
68
+ asyncio.run(main())
69
+ ```
70
+
71
+ ### Ticket Authentication
72
+
73
+ ```python
74
+ from casfa import create_casfa_client, CasfaClientConfig, TicketAuthConfig
75
+
76
+ async def process_with_ticket(ticket_id: str):
77
+ client = create_casfa_client(CasfaClientConfig(
78
+ base_url="https://casfa.example.com",
79
+ auth=TicketAuthConfig(type="ticket", ticket_id=ticket_id),
80
+ ))
81
+
82
+ # Read nodes allowed by ticket scope
83
+ result = await client.nodes.get(key="node:abc123...")
84
+ if result.ok:
85
+ data = result.data # bytes
86
+ # Process data...
87
+
88
+ # Commit output
89
+ result = await client.tickets.commit(
90
+ ticket_id=ticket_id,
91
+ output="node:result123...",
92
+ )
93
+
94
+ await client.close()
95
+ ```
96
+
97
+ ## API Reference
98
+
99
+ ### Client Creation
100
+
101
+ ```python
102
+ from casfa import create_casfa_client, CasfaClientConfig
103
+
104
+ client = create_casfa_client(CasfaClientConfig(
105
+ base_url="https://casfa.example.com",
106
+ auth=auth_config, # TokenAuthConfig, TicketAuthConfig, etc.
107
+ realm_id="user:ABC123", # Optional
108
+ ))
109
+ ```
110
+
111
+ ### API Namespaces
112
+
113
+ | Namespace | Description |
114
+ |-----------|-------------|
115
+ | `client.oauth` | OAuth/Cognito authentication |
116
+ | `client.auth` | AWP clients and Agent tokens |
117
+ | `client.admin` | Admin user management |
118
+ | `client.mcp` | MCP JSON-RPC tool calls |
119
+ | `client.realm` | Realm info and usage |
120
+ | `client.tickets` | Ticket management |
121
+ | `client.depots` | Depot management |
122
+ | `client.nodes` | Node storage operations |
123
+
124
+ ### Result Pattern
125
+
126
+ All API methods return `FetchResult[T]`:
127
+
128
+ ```python
129
+ result = await client.tickets.create(...)
130
+
131
+ if result.ok:
132
+ ticket = result.data # TicketInfo
133
+ print(ticket.ticket_id)
134
+ else:
135
+ error = result.error # CasfaError
136
+ print(f"Error: {error.code} - {error.message}")
137
+ ```
138
+
139
+ ### Authentication Types
140
+
141
+ | Type | Config | Header |
142
+ |------|--------|--------|
143
+ | Agent Token | `TokenAuthConfig` | `AgentToken {token}` |
144
+ | Ticket | `TicketAuthConfig` | `Ticket {ticketId}` |
145
+ | User OAuth | `UserAuthConfig` | `Bearer {accessToken}` |
146
+ | P256 (AWP) | `P256AuthConfig` | `X-AWP-*` headers |
147
+
148
+ ## Development
149
+
150
+ ```bash
151
+ # Install dev dependencies
152
+ pip install -e ".[dev]"
153
+
154
+ # Run tests
155
+ pytest
156
+
157
+ # Type check
158
+ mypy casfa
159
+
160
+ # Lint
161
+ ruff check casfa
162
+ ```
163
+
164
+ ## License
165
+
166
+ MIT
@@ -0,0 +1,141 @@
1
+ # CASFA Python SDK
2
+
3
+ Python client for CASFA (Content-Addressable Storage for Agents).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install casfa-client
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### Agent Token Authentication
14
+
15
+ ```python
16
+ import asyncio
17
+ from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
18
+
19
+ async def main():
20
+ # Create client with agent token
21
+ client = create_casfa_client(CasfaClientConfig(
22
+ base_url="https://casfa.example.com",
23
+ auth=TokenAuthConfig(type="token", token="casfa_xxx"),
24
+ realm_id="user:ABC123",
25
+ ))
26
+
27
+ # Get realm usage
28
+ result = await client.realm.get_usage()
29
+ if result.ok:
30
+ print(f"Nodes: {result.data.node_count}")
31
+ print(f"Bytes: {result.data.total_bytes}")
32
+ else:
33
+ print(f"Error: {result.error.message}")
34
+
35
+ # List depots
36
+ result = await client.depots.list()
37
+ if result.ok:
38
+ for depot in result.data.items:
39
+ print(f"Depot: {depot.title} (v{depot.version})")
40
+
41
+ await client.close()
42
+
43
+ asyncio.run(main())
44
+ ```
45
+
46
+ ### Ticket Authentication
47
+
48
+ ```python
49
+ from casfa import create_casfa_client, CasfaClientConfig, TicketAuthConfig
50
+
51
+ async def process_with_ticket(ticket_id: str):
52
+ client = create_casfa_client(CasfaClientConfig(
53
+ base_url="https://casfa.example.com",
54
+ auth=TicketAuthConfig(type="ticket", ticket_id=ticket_id),
55
+ ))
56
+
57
+ # Read nodes allowed by ticket scope
58
+ result = await client.nodes.get(key="node:abc123...")
59
+ if result.ok:
60
+ data = result.data # bytes
61
+ # Process data...
62
+
63
+ # Commit output
64
+ result = await client.tickets.commit(
65
+ ticket_id=ticket_id,
66
+ output="node:result123...",
67
+ )
68
+
69
+ await client.close()
70
+ ```
71
+
72
+ ## API Reference
73
+
74
+ ### Client Creation
75
+
76
+ ```python
77
+ from casfa import create_casfa_client, CasfaClientConfig
78
+
79
+ client = create_casfa_client(CasfaClientConfig(
80
+ base_url="https://casfa.example.com",
81
+ auth=auth_config, # TokenAuthConfig, TicketAuthConfig, etc.
82
+ realm_id="user:ABC123", # Optional
83
+ ))
84
+ ```
85
+
86
+ ### API Namespaces
87
+
88
+ | Namespace | Description |
89
+ |-----------|-------------|
90
+ | `client.oauth` | OAuth/Cognito authentication |
91
+ | `client.auth` | AWP clients and Agent tokens |
92
+ | `client.admin` | Admin user management |
93
+ | `client.mcp` | MCP JSON-RPC tool calls |
94
+ | `client.realm` | Realm info and usage |
95
+ | `client.tickets` | Ticket management |
96
+ | `client.depots` | Depot management |
97
+ | `client.nodes` | Node storage operations |
98
+
99
+ ### Result Pattern
100
+
101
+ All API methods return `FetchResult[T]`:
102
+
103
+ ```python
104
+ result = await client.tickets.create(...)
105
+
106
+ if result.ok:
107
+ ticket = result.data # TicketInfo
108
+ print(ticket.ticket_id)
109
+ else:
110
+ error = result.error # CasfaError
111
+ print(f"Error: {error.code} - {error.message}")
112
+ ```
113
+
114
+ ### Authentication Types
115
+
116
+ | Type | Config | Header |
117
+ |------|--------|--------|
118
+ | Agent Token | `TokenAuthConfig` | `AgentToken {token}` |
119
+ | Ticket | `TicketAuthConfig` | `Ticket {ticketId}` |
120
+ | User OAuth | `UserAuthConfig` | `Bearer {accessToken}` |
121
+ | P256 (AWP) | `P256AuthConfig` | `X-AWP-*` headers |
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ # Install dev dependencies
127
+ pip install -e ".[dev]"
128
+
129
+ # Run tests
130
+ pytest
131
+
132
+ # Type check
133
+ mypy casfa
134
+
135
+ # Lint
136
+ ruff check casfa
137
+ ```
138
+
139
+ ## License
140
+
141
+ MIT
@@ -0,0 +1,227 @@
1
+ """CASFA Python SDK - Content-Addressable Storage for Agents.
2
+
3
+ This SDK provides a Python client for interacting with the CASFA API,
4
+ mirroring the TypeScript Client V2 (`@agent-web-portal/casfa-client-v2`).
5
+
6
+ Example:
7
+ >>> from casfa import create_casfa_client, CasfaClientConfig, TokenAuthConfig
8
+ >>>
9
+ >>> client = create_casfa_client(CasfaClientConfig(
10
+ ... base_url="https://casfa.example.com",
11
+ ... auth=TokenAuthConfig(type="token", token="casfa_xxx"),
12
+ ... realm_id="user:ABC123",
13
+ ... ))
14
+ >>>
15
+ >>> # Get realm usage
16
+ >>> result = await client.realm.get_usage()
17
+ >>> if result.ok:
18
+ ... print(f"Nodes: {result.data.node_count}")
19
+ ...
20
+ >>> # Create a ticket
21
+ >>> result = await client.tickets.create(
22
+ ... input=["node:abc123..."],
23
+ ... purpose="Process data",
24
+ ... )
25
+ """
26
+
27
+ # =============================================================================
28
+ # Main Client
29
+ # =============================================================================
30
+
31
+ from casfa.auth.p256 import P256Auth, create_p256_auth
32
+ from casfa.auth.permissions import (
33
+ API_PERMISSIONS,
34
+ ApiName,
35
+ PermissionCheckResult,
36
+ assert_access,
37
+ can_access,
38
+ check_permission,
39
+ get_required_auth,
40
+ is_public_api,
41
+ )
42
+ from casfa.auth.ticket import TicketAuth, create_ticket_auth
43
+ from casfa.auth.token import TokenAuth, create_token_auth
44
+
45
+ # =============================================================================
46
+ # Auth Strategies
47
+ # =============================================================================
48
+ from casfa.auth.user import UserAuth, create_user_auth
49
+ from casfa.client import CasfaClient, CasfaClientConfig, create_casfa_client
50
+
51
+ # =============================================================================
52
+ # Types - API
53
+ # =============================================================================
54
+ from casfa.types.api import (
55
+ # Agent Token
56
+ AgentTokenInfo,
57
+ # AWP Client
58
+ AwpAuthInitResponse,
59
+ AwpAuthPollResponse,
60
+ AwpClientInfo,
61
+ # OAuth
62
+ CognitoConfig,
63
+ CreateAgentTokenResponse,
64
+ DepotDetail,
65
+ DepotHistoryEntry,
66
+ # Depot
67
+ DepotInfo,
68
+ DictNodeMetadata,
69
+ FileNodeMetadata,
70
+ McpError,
71
+ # MCP
72
+ McpRequest,
73
+ McpResponse,
74
+ NodeKind,
75
+ # Node
76
+ NodeMetadata,
77
+ # Pagination
78
+ PaginatedResponse,
79
+ PrepareNodesResult,
80
+ # Realm
81
+ RealmInfo,
82
+ RealmUsage,
83
+ SuccessorNodeMetadata,
84
+ # Ticket
85
+ TicketInfo,
86
+ TicketListItem,
87
+ TokenResponse,
88
+ UserInfo,
89
+ # Admin
90
+ UserListItem,
91
+ WritableConfig,
92
+ )
93
+
94
+ # =============================================================================
95
+ # Types - Auth
96
+ # =============================================================================
97
+ from casfa.types.auth import (
98
+ AuthConfig,
99
+ AuthState,
100
+ AuthType,
101
+ # P256
102
+ P256AuthCallbacks,
103
+ P256AuthConfig,
104
+ P256AuthState,
105
+ P256PollStatus,
106
+ TicketAuthConfig,
107
+ # Ticket
108
+ TicketAuthState,
109
+ TokenAuthConfig,
110
+ # Token
111
+ TokenAuthState,
112
+ # User
113
+ UserAuthCallbacks,
114
+ UserAuthConfig,
115
+ UserAuthState,
116
+ )
117
+
118
+ # =============================================================================
119
+ # Types - Providers
120
+ # =============================================================================
121
+ from casfa.types.providers import (
122
+ HashProvider,
123
+ KeyPairProvider,
124
+ P256KeyPair,
125
+ StorageProvider,
126
+ )
127
+
128
+ # =============================================================================
129
+ # Utils
130
+ # =============================================================================
131
+ from casfa.utils.errors import (
132
+ CasfaError,
133
+ CasfaErrorCode,
134
+ create_error,
135
+ is_casfa_error,
136
+ )
137
+ from casfa.utils.fetch import FetchResult, FetchResultErr, FetchResultOk
138
+
139
+ # =============================================================================
140
+ # Version
141
+ # =============================================================================
142
+
143
+ __version__ = "0.1.0"
144
+
145
+ __all__ = [
146
+ # Client
147
+ "CasfaClient",
148
+ "CasfaClientConfig",
149
+ "create_casfa_client",
150
+ # API Types
151
+ "CognitoConfig",
152
+ "TokenResponse",
153
+ "UserInfo",
154
+ "AwpAuthInitResponse",
155
+ "AwpAuthPollResponse",
156
+ "AwpClientInfo",
157
+ "AgentTokenInfo",
158
+ "CreateAgentTokenResponse",
159
+ "UserListItem",
160
+ "RealmInfo",
161
+ "RealmUsage",
162
+ "TicketInfo",
163
+ "TicketListItem",
164
+ "WritableConfig",
165
+ "DepotInfo",
166
+ "DepotDetail",
167
+ "DepotHistoryEntry",
168
+ "NodeMetadata",
169
+ "DictNodeMetadata",
170
+ "FileNodeMetadata",
171
+ "SuccessorNodeMetadata",
172
+ "NodeKind",
173
+ "PrepareNodesResult",
174
+ "McpRequest",
175
+ "McpResponse",
176
+ "McpError",
177
+ "PaginatedResponse",
178
+ # Auth Types
179
+ "AuthConfig",
180
+ "AuthState",
181
+ "AuthType",
182
+ "UserAuthCallbacks",
183
+ "UserAuthState",
184
+ "UserAuthConfig",
185
+ "TokenAuthState",
186
+ "TokenAuthConfig",
187
+ "TicketAuthState",
188
+ "TicketAuthConfig",
189
+ "P256AuthCallbacks",
190
+ "P256AuthState",
191
+ "P256AuthConfig",
192
+ "P256PollStatus",
193
+ # Provider Types
194
+ "StorageProvider",
195
+ "HashProvider",
196
+ "KeyPairProvider",
197
+ "P256KeyPair",
198
+ # Auth Strategies
199
+ "UserAuth",
200
+ "create_user_auth",
201
+ "TokenAuth",
202
+ "create_token_auth",
203
+ "TicketAuth",
204
+ "create_ticket_auth",
205
+ "P256Auth",
206
+ "create_p256_auth",
207
+ # Permissions
208
+ "ApiName",
209
+ "API_PERMISSIONS",
210
+ "can_access",
211
+ "assert_access",
212
+ "get_required_auth",
213
+ "is_public_api",
214
+ "check_permission",
215
+ "PermissionCheckResult",
216
+ # Errors
217
+ "CasfaError",
218
+ "CasfaErrorCode",
219
+ "create_error",
220
+ "is_casfa_error",
221
+ # Fetch Result
222
+ "FetchResult",
223
+ "FetchResultOk",
224
+ "FetchResultErr",
225
+ # Version
226
+ "__version__",
227
+ ]
@@ -0,0 +1,21 @@
1
+ """CASFA API namespaces."""
2
+
3
+ from casfa.api.admin import AdminApi
4
+ from casfa.api.auth import AuthApi
5
+ from casfa.api.depots import DepotApi
6
+ from casfa.api.mcp import McpApi
7
+ from casfa.api.nodes import NodeApi
8
+ from casfa.api.oauth import OAuthApi
9
+ from casfa.api.realm import RealmApi
10
+ from casfa.api.tickets import TicketApi
11
+
12
+ __all__ = [
13
+ "OAuthApi",
14
+ "AuthApi",
15
+ "AdminApi",
16
+ "McpApi",
17
+ "RealmApi",
18
+ "TicketApi",
19
+ "DepotApi",
20
+ "NodeApi",
21
+ ]
@@ -0,0 +1,81 @@
1
+ """Admin API - User management for admins."""
2
+
3
+ from casfa.types.api import PaginatedResponse, UserListItem
4
+ from casfa.utils.fetch import Fetcher, FetchResult, FetchResultOk, RequestOptions
5
+
6
+
7
+ class AdminApi:
8
+ """Admin API namespace for user management."""
9
+
10
+ def __init__(self, fetcher: Fetcher) -> None:
11
+ self._fetcher = fetcher
12
+
13
+ async def list_users(
14
+ self,
15
+ *,
16
+ cursor: str | None = None,
17
+ limit: int | None = None,
18
+ ) -> FetchResult[PaginatedResponse[UserListItem]]:
19
+ """List all users (admin only)."""
20
+ params = []
21
+ if cursor:
22
+ params.append(f"cursor={cursor}")
23
+ if limit:
24
+ params.append(f"limit={limit}")
25
+
26
+ path = "/api/admin/users"
27
+ if params:
28
+ path += "?" + "&".join(params)
29
+
30
+ result = await self._fetcher.request(path)
31
+ if result.ok:
32
+ data = result.data
33
+ items = [
34
+ UserListItem(
35
+ user_id=item["user_id"],
36
+ email=item["email"],
37
+ role=item["role"],
38
+ created_at=item["created_at"],
39
+ realm_id=item.get("realm_id"),
40
+ )
41
+ for item in data.get("items", [])
42
+ ]
43
+ return FetchResultOk(
44
+ ok=True,
45
+ data=PaginatedResponse(
46
+ items=items,
47
+ next_cursor=data.get("next_cursor"),
48
+ total=data.get("total"),
49
+ ),
50
+ status=result.status,
51
+ )
52
+ return result
53
+
54
+ async def update_user_role(
55
+ self,
56
+ *,
57
+ user_id: str,
58
+ role: str,
59
+ ) -> FetchResult[UserListItem]:
60
+ """Update a user's role (admin only)."""
61
+ result = await self._fetcher.request(
62
+ f"/api/admin/users/{user_id}/role",
63
+ RequestOptions(
64
+ method="PUT",
65
+ body={"role": role},
66
+ ),
67
+ )
68
+ if result.ok:
69
+ data = result.data
70
+ return FetchResultOk(
71
+ ok=True,
72
+ data=UserListItem(
73
+ user_id=data["user_id"],
74
+ email=data["email"],
75
+ role=data["role"],
76
+ created_at=data["created_at"],
77
+ realm_id=data.get("realm_id"),
78
+ ),
79
+ status=result.status,
80
+ )
81
+ return result