phaseo 2.0.5__tar.gz → 2.0.7__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,4 @@
1
+ dist/
2
+ *.egg-info/
3
+ __pycache__/
4
+ .pytest_cache/
phaseo-2.0.7/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Daniel Butler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
phaseo-2.0.7/NOTICE ADDED
@@ -0,0 +1,7 @@
1
+ Phaseo - Official SDK for JavaScript and TypeScript
2
+ Copyright (c) 2025 Daniel Butler
3
+
4
+ Licensed under the MIT Licence.
5
+ See the LICENSE file in this directory for details.
6
+
7
+ This product includes software developed by Phaseo (https://phaseo.app).
phaseo-2.0.7/PKG-INFO ADDED
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: phaseo
3
+ Version: 2.0.7
4
+ Summary: Phaseo Gateway SDK for Python.
5
+ Project-URL: Homepage, https://phaseo.app
6
+ Project-URL: Documentation, https://phaseo.app
7
+ Project-URL: Repository, https://github.com/phaseoteam/Phaseo
8
+ Project-URL: Issues, https://github.com/phaseoteam/Phaseo/issues
9
+ Author-email: Phaseo <danielbutler500@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ License-File: NOTICE
13
+ Keywords: ai,gateway,llm,sdk
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: httpx<1.0.0,>=0.27.2
22
+ Requires-Dist: pydantic<3.0,>=2.6
23
+ Requires-Dist: python-dateutil<3.0,>=2.9
24
+ Requires-Dist: typing-extensions>=4.8.0
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Phaseo Python SDK
28
+
29
+ Official Python SDK for Phaseo Gateway.
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install phaseo
35
+ ```
36
+
37
+ Requires Python 3.10+.
38
+
39
+ ## Quick start
40
+
41
+ ```python
42
+ from phaseo import Phaseo
43
+
44
+ client = Phaseo() # Uses PHASEO_API_KEY from environment
45
+
46
+ response = client.responses.create(
47
+ {
48
+ "model": "google/gemma-3-27b:free",
49
+ "input": "Reply with: Python SDK works",
50
+ }
51
+ )
52
+
53
+ print(response.get("output_text"))
54
+ ```
55
+
56
+ ## Streaming example
57
+
58
+ ```python
59
+ from phaseo import Phaseo
60
+
61
+ client = Phaseo()
62
+
63
+ response = ""
64
+ for chunk in client.stream_chat(
65
+ {
66
+ "model": "google/gemma-3-27b:free",
67
+ "messages": [{"role": "user", "content": "Stream hi"}],
68
+ }
69
+ ):
70
+ if chunk.get("text"):
71
+ response += chunk["text"]
72
+ print(chunk["text"], end="", flush=True)
73
+
74
+ if chunk.get("reasoning_tokens"):
75
+ print("\nReasoning tokens:", chunk["reasoning_tokens"])
76
+ ```
77
+
78
+ ## Common methods
79
+
80
+ - `client.responses.create(...)`
81
+ - `client.chat.completions.create(...)`
82
+ - `client.messages.create(...)`
83
+ - `client.stream_chat(...)`, `client.stream_responses(...)`, and `client.stream_message(...)` for parsed streaming chunks with `text`, `usage`, and `reasoning_tokens`
84
+ - `client.models.list(...)`
85
+ - `client.list_organisations(...)` for paginated `/organisations` discovery
86
+ - `client.list_pricing_models(...)` for `/pricing/models` catalogue pricing discovery
87
+ - `client.calculate_pricing(...)` for `/pricing/calculate` usage estimation
88
+ - `client.list_providers(...)`, `client.get_credits(...)`, `client.get_activity(...)`, and `client.get_analytics(...)` for provider discovery and management-key usage surfaces
89
+ - `client.list_api_keys(...)` for management-key `/keys` discovery
90
+ - `client.create_api_key(...)`, `client.update_api_key(key_id, ...)`, and `client.delete_api_key(key_id)` for management-key API-key lifecycle changes
91
+ - `client.get_api_key(key_id)` for management-key `/keys/{id}` lookup
92
+ - `client.list_workspaces(...)`, `client.get_workspace(workspace_id)`, `client.create_workspace(...)`, `client.update_workspace(workspace_id, ...)`, and `client.delete_workspace(workspace_id)` for management-key workspace lifecycle management
93
+ - `client.get_current_api_key()`
94
+ - `client.get_health()`
95
+ - `client.models.get_deprecation_info(model_id)`
96
+ - `client.models.validate(model_id)`
97
+ - `client.batches.list_models()` for batch-capable models and supported batch parameter metadata
98
+
99
+ Model discovery supports the public `/models` filters, including `provider`, `provider_status`, `provider_routing_status`, `model_routing_status`, `capability_status`, `provider_availability_status`, `provider_availability_reason`, `status`, `organisation`, `endpoints`, `input_types`, `output_types`, `params`, `availability`, `limit`, and `offset`.
100
+
101
+ Use `provider_availability_reason` with `availability="all"` when you want rollout-state entries such as `preview_only`, `provider_not_ready`, `gated`, `access_limited`, `region_limited`, `project_limited`, `paused`, or `soft_blocked`. Use `capability_status` with `availability="all"` when you want non-routable endpoint mappings such as `coming_soon` or `internal_testing`.
102
+
103
+ ```python
104
+ models = client.get_models({
105
+ "provider": ["anthropic"],
106
+ "provider_status": ["beta", "not_ready"],
107
+ "provider_availability_reason": ["preview_only", "provider_not_ready"],
108
+ "capability_status": ["coming_soon", "internal_testing"],
109
+ "availability": "all",
110
+ })
111
+ ```
112
+
113
+ ## Async job websocket helpers
114
+
115
+ Batch and video operations can expose a websocket lifecycle stream at `/v1/async/{kind}/{id}/ws`.
116
+ Create responses include the job id, polling URL, optional websocket URL, and sanitized webhook delivery state.
117
+
118
+ ```python
119
+ import os
120
+
121
+ batch = client.batches.create({
122
+ "endpoint": "/v1/responses",
123
+ "input_file_id": "file_123",
124
+ "completion_window": "24h",
125
+ "webhook": {
126
+ "url": "https://example.com/phaseo/webhooks",
127
+ "secret": os.environ["PHASEO_WEBHOOK_SECRET"],
128
+ "events": ["batch.progress", "batch.completed", "batch.failed"],
129
+ },
130
+ })
131
+
132
+ video = client.videos.create({
133
+ "model": "google/veo-3",
134
+ "prompt": "orbital reveal",
135
+ "webhook": {
136
+ "url": "https://example.com/phaseo/webhooks",
137
+ "secret": os.environ["PHASEO_WEBHOOK_SECRET"],
138
+ "events": ["video.progress", "video.completed", "video.failed"],
139
+ },
140
+ })
141
+ ```
142
+
143
+ ```python
144
+ batch_socket_url = client.batches.websocket_url("batch_123", interval_ms=1500)
145
+
146
+ video_socket_url = client.videos.websocket_url(
147
+ "video_123",
148
+ close_on_terminal=True,
149
+ )
150
+
151
+ generic_socket_url = client.get_async_job_websocket_url("video", "video_123")
152
+ ```
153
+
154
+ ## Free and paid models
155
+
156
+ - Models with `:free` in the model ID can be called with zero deposited credits.
157
+ - Paid models require available wallet balance.
158
+
159
+ ## Model lifecycle warnings
160
+
161
+ ```python
162
+ from phaseo import Phaseo
163
+
164
+ client = Phaseo(
165
+ enable_deprecation_warnings=True,
166
+ warnings_as_errors=False,
167
+ logger=lambda level, message, meta: print(level, message, meta),
168
+ )
169
+ ```
170
+
171
+ ## Environment variables
172
+
173
+ - `PHASEO_API_KEY` (required unless passed in code)
174
+ - `PHASEO_BASE_URL` (optional, defaults to `https://api.phaseo.app/v1`)
175
+
176
+ ## Devtools
177
+
178
+ ```python
179
+ from phaseo import Phaseo, create_phaseo_devtools
180
+
181
+ client = Phaseo(
182
+ devtools=create_phaseo_devtools(
183
+ directory=".phaseo-devtools",
184
+ capture_headers=False,
185
+ )
186
+ )
187
+ ```
188
+
189
+ ## Regeneration and local checks
190
+
191
+ - Regenerate generated client: `pnpm openapi:gen:py`
192
+ - Run tests: `pnpm test:sdk-py`
193
+ - Smoke checks:
194
+ - `pnpm --filter @phaseo/py-sdk run smoke:chat`
195
+ - `pnpm --filter @phaseo/py-sdk run smoke:responses`
phaseo-2.0.7/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # Phaseo Python SDK
2
+
3
+ Official Python SDK for Phaseo Gateway.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install phaseo
9
+ ```
10
+
11
+ Requires Python 3.10+.
12
+
13
+ ## Quick start
14
+
15
+ ```python
16
+ from phaseo import Phaseo
17
+
18
+ client = Phaseo() # Uses PHASEO_API_KEY from environment
19
+
20
+ response = client.responses.create(
21
+ {
22
+ "model": "google/gemma-3-27b:free",
23
+ "input": "Reply with: Python SDK works",
24
+ }
25
+ )
26
+
27
+ print(response.get("output_text"))
28
+ ```
29
+
30
+ ## Streaming example
31
+
32
+ ```python
33
+ from phaseo import Phaseo
34
+
35
+ client = Phaseo()
36
+
37
+ response = ""
38
+ for chunk in client.stream_chat(
39
+ {
40
+ "model": "google/gemma-3-27b:free",
41
+ "messages": [{"role": "user", "content": "Stream hi"}],
42
+ }
43
+ ):
44
+ if chunk.get("text"):
45
+ response += chunk["text"]
46
+ print(chunk["text"], end="", flush=True)
47
+
48
+ if chunk.get("reasoning_tokens"):
49
+ print("\nReasoning tokens:", chunk["reasoning_tokens"])
50
+ ```
51
+
52
+ ## Common methods
53
+
54
+ - `client.responses.create(...)`
55
+ - `client.chat.completions.create(...)`
56
+ - `client.messages.create(...)`
57
+ - `client.stream_chat(...)`, `client.stream_responses(...)`, and `client.stream_message(...)` for parsed streaming chunks with `text`, `usage`, and `reasoning_tokens`
58
+ - `client.models.list(...)`
59
+ - `client.list_organisations(...)` for paginated `/organisations` discovery
60
+ - `client.list_pricing_models(...)` for `/pricing/models` catalogue pricing discovery
61
+ - `client.calculate_pricing(...)` for `/pricing/calculate` usage estimation
62
+ - `client.list_providers(...)`, `client.get_credits(...)`, `client.get_activity(...)`, and `client.get_analytics(...)` for provider discovery and management-key usage surfaces
63
+ - `client.list_api_keys(...)` for management-key `/keys` discovery
64
+ - `client.create_api_key(...)`, `client.update_api_key(key_id, ...)`, and `client.delete_api_key(key_id)` for management-key API-key lifecycle changes
65
+ - `client.get_api_key(key_id)` for management-key `/keys/{id}` lookup
66
+ - `client.list_workspaces(...)`, `client.get_workspace(workspace_id)`, `client.create_workspace(...)`, `client.update_workspace(workspace_id, ...)`, and `client.delete_workspace(workspace_id)` for management-key workspace lifecycle management
67
+ - `client.get_current_api_key()`
68
+ - `client.get_health()`
69
+ - `client.models.get_deprecation_info(model_id)`
70
+ - `client.models.validate(model_id)`
71
+ - `client.batches.list_models()` for batch-capable models and supported batch parameter metadata
72
+
73
+ Model discovery supports the public `/models` filters, including `provider`, `provider_status`, `provider_routing_status`, `model_routing_status`, `capability_status`, `provider_availability_status`, `provider_availability_reason`, `status`, `organisation`, `endpoints`, `input_types`, `output_types`, `params`, `availability`, `limit`, and `offset`.
74
+
75
+ Use `provider_availability_reason` with `availability="all"` when you want rollout-state entries such as `preview_only`, `provider_not_ready`, `gated`, `access_limited`, `region_limited`, `project_limited`, `paused`, or `soft_blocked`. Use `capability_status` with `availability="all"` when you want non-routable endpoint mappings such as `coming_soon` or `internal_testing`.
76
+
77
+ ```python
78
+ models = client.get_models({
79
+ "provider": ["anthropic"],
80
+ "provider_status": ["beta", "not_ready"],
81
+ "provider_availability_reason": ["preview_only", "provider_not_ready"],
82
+ "capability_status": ["coming_soon", "internal_testing"],
83
+ "availability": "all",
84
+ })
85
+ ```
86
+
87
+ ## Async job websocket helpers
88
+
89
+ Batch and video operations can expose a websocket lifecycle stream at `/v1/async/{kind}/{id}/ws`.
90
+ Create responses include the job id, polling URL, optional websocket URL, and sanitized webhook delivery state.
91
+
92
+ ```python
93
+ import os
94
+
95
+ batch = client.batches.create({
96
+ "endpoint": "/v1/responses",
97
+ "input_file_id": "file_123",
98
+ "completion_window": "24h",
99
+ "webhook": {
100
+ "url": "https://example.com/phaseo/webhooks",
101
+ "secret": os.environ["PHASEO_WEBHOOK_SECRET"],
102
+ "events": ["batch.progress", "batch.completed", "batch.failed"],
103
+ },
104
+ })
105
+
106
+ video = client.videos.create({
107
+ "model": "google/veo-3",
108
+ "prompt": "orbital reveal",
109
+ "webhook": {
110
+ "url": "https://example.com/phaseo/webhooks",
111
+ "secret": os.environ["PHASEO_WEBHOOK_SECRET"],
112
+ "events": ["video.progress", "video.completed", "video.failed"],
113
+ },
114
+ })
115
+ ```
116
+
117
+ ```python
118
+ batch_socket_url = client.batches.websocket_url("batch_123", interval_ms=1500)
119
+
120
+ video_socket_url = client.videos.websocket_url(
121
+ "video_123",
122
+ close_on_terminal=True,
123
+ )
124
+
125
+ generic_socket_url = client.get_async_job_websocket_url("video", "video_123")
126
+ ```
127
+
128
+ ## Free and paid models
129
+
130
+ - Models with `:free` in the model ID can be called with zero deposited credits.
131
+ - Paid models require available wallet balance.
132
+
133
+ ## Model lifecycle warnings
134
+
135
+ ```python
136
+ from phaseo import Phaseo
137
+
138
+ client = Phaseo(
139
+ enable_deprecation_warnings=True,
140
+ warnings_as_errors=False,
141
+ logger=lambda level, message, meta: print(level, message, meta),
142
+ )
143
+ ```
144
+
145
+ ## Environment variables
146
+
147
+ - `PHASEO_API_KEY` (required unless passed in code)
148
+ - `PHASEO_BASE_URL` (optional, defaults to `https://api.phaseo.app/v1`)
149
+
150
+ ## Devtools
151
+
152
+ ```python
153
+ from phaseo import Phaseo, create_phaseo_devtools
154
+
155
+ client = Phaseo(
156
+ devtools=create_phaseo_devtools(
157
+ directory=".phaseo-devtools",
158
+ capture_headers=False,
159
+ )
160
+ )
161
+ ```
162
+
163
+ ## Regeneration and local checks
164
+
165
+ - Regenerate generated client: `pnpm openapi:gen:py`
166
+ - Run tests: `pnpm test:sdk-py`
167
+ - Smoke checks:
168
+ - `pnpm --filter @phaseo/py-sdk run smoke:chat`
169
+ - `pnpm --filter @phaseo/py-sdk run smoke:responses`
phaseo-2.0.7/SKILL.md ADDED
@@ -0,0 +1,8 @@
1
+ # Phaseo Python SDK (`phaseo`)
2
+
3
+ - Use `from phaseo import Phaseo`.
4
+ - Read credentials from `PHASEO_API_KEY`.
5
+ - Prefer `generate_response` for new text and multimodal integrations.
6
+ - Use preset slugs when your application has shared prompt, routing, or parameter defaults.
7
+ - Store async video job ids and poll status until terminal.
8
+ - Log request ids and model ids when debugging gateway behavior.
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "phaseo"
7
+ version = "2.0.7"
8
+ description = "Phaseo Gateway SDK for Python."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Phaseo", email = "danielbutler500@gmail.com" }]
13
+ keywords = ["ai", "sdk", "llm", "gateway"]
14
+ classifiers = [
15
+ "Development Status :: 5 - Production/Stable",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3 :: Only",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Typing :: Typed",
21
+ ]
22
+ dependencies = [
23
+ "httpx>=0.27.2,<1.0.0",
24
+ "typing-extensions>=4.8.0",
25
+ "pydantic>=2.6,<3.0",
26
+ "python-dateutil>=2.9,<3.0",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://phaseo.app"
31
+ Documentation = "https://phaseo.app"
32
+ Repository = "https://github.com/phaseoteam/Phaseo"
33
+ Issues = "https://github.com/phaseoteam/Phaseo/issues"
34
+
35
+ [tool.hatch.build.targets.sdist]
36
+ include = [
37
+ "src/phaseo",
38
+ "src/phaseo_devtools",
39
+ "src/gen",
40
+ "SKILL.md",
41
+ "README.md",
42
+ "LICENSE",
43
+ ]
44
+
45
+ [tool.hatch.build.targets.wheel]
46
+ packages = [
47
+ "src/phaseo",
48
+ "src/phaseo_devtools",
49
+ "src/gen",
50
+ ]
51
+
52
+ [tool.hatch.build.targets.wheel.force-include]
53
+ "SKILL.md" = "phaseo/SKILL.md"
54
+
55
+ [tool.hatch.version]
56
+ path = "src/phaseo/__init__.py"
57
+
@@ -0,0 +1,8 @@
1
+ {
2
+ "files": [
3
+ "__init__.py",
4
+ "client.py",
5
+ "models.py",
6
+ "operations.py"
7
+ ]
8
+ }
@@ -0,0 +1,9 @@
1
+ from .client import Client
2
+ from .operations import *
3
+ from .models import *
4
+
5
+ __all__ = [
6
+ "Client",
7
+ *operations___all__,
8
+ *models___all__,
9
+ ]
@@ -0,0 +1,38 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import urllib.parse
5
+ import urllib.request
6
+ from typing import Any, Dict, Optional
7
+
8
+
9
+ class Client:
10
+ def __init__(self, base_url: str, headers: Optional[Dict[str, str]] = None):
11
+ self._base_url = base_url.rstrip('/')
12
+ self._headers = headers or {}
13
+
14
+ def request(
15
+ self,
16
+ method: str,
17
+ path: str,
18
+ query: Optional[Dict[str, Any]] = None,
19
+ headers: Optional[Dict[str, str]] = None,
20
+ body: Optional[Any] = None,
21
+ ) -> Any:
22
+ url = f"{self._base_url}{path}"
23
+ if query:
24
+ url += "?" + urllib.parse.urlencode(query, doseq=True)
25
+ payload = None
26
+ request_headers = {"Accept": "application/json", **self._headers, **(headers or {})}
27
+ if body is not None:
28
+ payload = json.dumps(body).encode("utf-8")
29
+ request_headers["Content-Type"] = "application/json"
30
+ req = urllib.request.Request(url, data=payload, headers=request_headers, method=method.upper())
31
+ with urllib.request.urlopen(req) as resp:
32
+ raw = resp.read().decode("utf-8")
33
+ if not raw:
34
+ return None
35
+ try:
36
+ return json.loads(raw)
37
+ except json.JSONDecodeError:
38
+ return raw