dyno-phi 0.3.2__tar.gz → 0.4.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.
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/.gitignore +13 -2
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/PKG-INFO +20 -22
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/README.md +17 -16
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/pyproject.toml +3 -6
- dyno_phi-0.4.0/src/phi/_version.py +1 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/auth.py +19 -7
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/doctor.py +6 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/models.py +40 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/skills.py +35 -12
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/document_sync.py +1 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/config.py +6 -4
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/graph.py +1 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/_generated.py +5 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/job_types.py +5 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/runs.py +12 -2
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/oauth.py +1 -1
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/runs.py +31 -6
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/sequences.py +1 -0
- dyno_phi-0.3.2/CHANGELOG.md +0 -134
- dyno_phi-0.3.2/src/phi/_version.py +0 -1
- dyno_phi-0.3.2/tests/__init__.py +0 -0
- dyno_phi-0.3.2/tests/cli/__init__.py +0 -0
- dyno_phi-0.3.2/tests/cli/conftest.py +0 -20
- dyno_phi-0.3.2/tests/cli/test_artifacts.py +0 -201
- dyno_phi-0.3.2/tests/cli/test_audit.py +0 -125
- dyno_phi-0.3.2/tests/cli/test_auth.py +0 -502
- dyno_phi-0.3.2/tests/cli/test_cli_scaffold.py +0 -329
- dyno_phi-0.3.2/tests/cli/test_completion.py +0 -122
- dyno_phi-0.3.2/tests/cli/test_datasets.py +0 -263
- dyno_phi-0.3.2/tests/cli/test_doctor.py +0 -190
- dyno_phi-0.3.2/tests/cli/test_document_sync.py +0 -336
- dyno_phi-0.3.2/tests/cli/test_documents.py +0 -278
- dyno_phi-0.3.2/tests/cli/test_export.py +0 -162
- dyno_phi-0.3.2/tests/cli/test_jobs.py +0 -411
- dyno_phi-0.3.2/tests/cli/test_json_contract.py +0 -443
- dyno_phi-0.3.2/tests/cli/test_logs.py +0 -271
- dyno_phi-0.3.2/tests/cli/test_models_cmd.py +0 -117
- dyno_phi-0.3.2/tests/cli/test_params.py +0 -326
- dyno_phi-0.3.2/tests/cli/test_pipeline.py +0 -263
- dyno_phi-0.3.2/tests/cli/test_projects.py +0 -160
- dyno_phi-0.3.2/tests/cli/test_quickstart.py +0 -198
- dyno_phi-0.3.2/tests/cli/test_quota.py +0 -103
- dyno_phi-0.3.2/tests/cli/test_runs.py +0 -393
- dyno_phi-0.3.2/tests/cli/test_skills.py +0 -175
- dyno_phi-0.3.2/tests/conftest.py +0 -32
- dyno_phi-0.3.2/tests/live/__init__.py +0 -0
- dyno_phi-0.3.2/tests/live/conftest.py +0 -260
- dyno_phi-0.3.2/tests/live/test_live_artifacts_logs.py +0 -161
- dyno_phi-0.3.2/tests/live/test_live_auth_discovery.py +0 -126
- dyno_phi-0.3.2/tests/live/test_live_datasets_export.py +0 -150
- dyno_phi-0.3.2/tests/live/test_live_errors.py +0 -111
- dyno_phi-0.3.2/tests/live/test_live_jobs.py +0 -162
- dyno_phi-0.3.2/tests/live/test_live_pipelines.py +0 -177
- dyno_phi-0.3.2/tests/live/test_live_quickstart_sdk.py +0 -130
- dyno_phi-0.3.2/tests/test_artifacts.py +0 -81
- dyno_phi-0.3.2/tests/test_audit.py +0 -108
- dyno_phi-0.3.2/tests/test_billing.py +0 -87
- dyno_phi-0.3.2/tests/test_config.py +0 -142
- dyno_phi-0.3.2/tests/test_datasets.py +0 -400
- dyno_phi-0.3.2/tests/test_designs.py +0 -178
- dyno_phi-0.3.2/tests/test_docs_examples.py +0 -154
- dyno_phi-0.3.2/tests/test_documents.py +0 -290
- dyno_phi-0.3.2/tests/test_errors.py +0 -117
- dyno_phi-0.3.2/tests/test_files.py +0 -340
- dyno_phi-0.3.2/tests/test_graph.py +0 -409
- dyno_phi-0.3.2/tests/test_imports.py +0 -69
- dyno_phi-0.3.2/tests/test_job_types.py +0 -157
- dyno_phi-0.3.2/tests/test_jobs.py +0 -455
- dyno_phi-0.3.2/tests/test_logs.py +0 -144
- dyno_phi-0.3.2/tests/test_oauth.py +0 -657
- dyno_phi-0.3.2/tests/test_packaging.py +0 -152
- dyno_phi-0.3.2/tests/test_parity.py +0 -46
- dyno_phi-0.3.2/tests/test_projects.py +0 -201
- dyno_phi-0.3.2/tests/test_quota.py +0 -129
- dyno_phi-0.3.2/tests/test_run_admin.py +0 -74
- dyno_phi-0.3.2/tests/test_runs.py +0 -438
- dyno_phi-0.3.2/tests/test_schema_validation.py +0 -98
- dyno_phi-0.3.2/tests/test_sequences.py +0 -383
- dyno_phi-0.3.2/tests/test_tool_configs.py +0 -42
- dyno_phi-0.3.2/tests/test_transport.py +0 -351
- dyno_phi-0.3.2/tests/test_uploads.py +0 -56
- dyno_phi-0.3.2/tests/test_waiters.py +0 -318
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/README.md +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/async_concurrent.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/compose_dag.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/download_results.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/pipelines/fold_and_analyze.yaml +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/pipelines/mpnn_esmfold_alphafold.yaml +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/quickstart/README.md +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/quickstart/trp_cage.fasta +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/run_pipeline.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/examples/submit_fold.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/__init__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/_schema_validation.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/_transport.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/async_client.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/__init__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/__main__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/__init__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/artifacts.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/audit.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/billing.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/datasets.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/documents.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/export.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/jobs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/logs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/pipeline.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/projects.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/quickstart.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/quota.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/runs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/commands/use.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/completion.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/errors.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/main.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/params.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/render.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/cli/state.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/client.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/errors.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/files.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/__init__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/artifacts.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/audit.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/billing.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/common.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/datasets.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/designs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/documents.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/imports.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/jobs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/logs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/projects.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/quota.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/run_admin.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/sequences.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/models/tool_configs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/profiles.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/py.typed +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/__init__.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/artifacts.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/audit.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/billing.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/datasets.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/designs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/documents.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/files.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/imports.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/job_types.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/jobs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/logs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/projects.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/quota.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/run_admin.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/tool_configs.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/resources/uploads.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/schema_cache.py +0 -0
- {dyno_phi-0.3.2 → dyno_phi-0.4.0}/src/phi/waiters.py +0 -0
|
@@ -39,11 +39,15 @@ htmlcov/
|
|
|
39
39
|
*.json
|
|
40
40
|
!pyproject.json
|
|
41
41
|
!.cursor/environment.json
|
|
42
|
+
!tests/billing/quotes.json
|
|
42
43
|
!tests/fixtures/metrics/ipsae_nonzero_multisubchain.json
|
|
43
44
|
!tests/fixtures/bindcraft/run_metadata.json
|
|
44
45
|
!clients/phi/tests/fixtures/job_types.json
|
|
45
46
|
!clients/phi/tests/fixtures/run_pipelines.json
|
|
46
47
|
!experiments/campaigns/y7_design/config/score_hit_calibration.json
|
|
48
|
+
!infrastructure/terraform/*/release.auto.tfvars.json
|
|
49
|
+
!.github/deploy-environments.json
|
|
50
|
+
!infrastructure/k8s/runner/h100-reservations.json
|
|
47
51
|
# Anchored to the repo root so it only blocks a top-level credential dir,
|
|
48
52
|
# not source packages that happen to be named `secrets/`.
|
|
49
53
|
/secrets/
|
|
@@ -77,14 +81,21 @@ infrastructure/**/terraform.tfstate.backup
|
|
|
77
81
|
infrastructure/**/*.tfvars
|
|
78
82
|
!infrastructure/**/terraform.tfvars.example
|
|
79
83
|
# Committed env var files — no secrets here; image_tag is always CI-supplied
|
|
80
|
-
!infrastructure/terraform/staging.tfvars
|
|
81
|
-
!infrastructure/terraform/production.tfvars
|
|
84
|
+
!infrastructure/terraform/legacy/staging.tfvars
|
|
85
|
+
!infrastructure/terraform/legacy/production.tfvars
|
|
86
|
+
!infrastructure/terraform/*/terraform.tfvars
|
|
82
87
|
infrastructure/**/.terraform.lock.hcl
|
|
88
|
+
# Digger workspaces pin their providers
|
|
89
|
+
!infrastructure/terraform/dev/.terraform.lock.hcl
|
|
90
|
+
!infrastructure/terraform/staging/.terraform.lock.hcl
|
|
91
|
+
!infrastructure/terraform/prod/.terraform.lock.hcl
|
|
83
92
|
|
|
84
93
|
# Cloud Build local artifacts
|
|
85
94
|
cloudbuild/*.log
|
|
86
95
|
/runners/capsid-fold-esmfold2-base/source-artifact.zip
|
|
87
96
|
/runners/capsid-fold-esmfold2-base/source-artifact.sha256
|
|
97
|
+
/runners/capsid-fold-openfold3-base/source-artifact.zip
|
|
98
|
+
/runners/capsid-fold-openfold3-base/source-artifact.sha256
|
|
88
99
|
|
|
89
100
|
# Docker
|
|
90
101
|
.dockerignore.local
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dyno-phi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Phi — Python SDK and CLI for the Phi protein design API
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Documentation, https://
|
|
7
|
-
Project-URL: Source, https://github.com/dynotx/phi-api/tree/main/clients/phi
|
|
8
|
-
Project-URL: Changelog, https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md
|
|
9
|
-
Project-URL: Issues, https://github.com/dynotx/phi-api/issues
|
|
5
|
+
Project-URL: Homepage, https://dynophi.com
|
|
6
|
+
Project-URL: Documentation, https://dynophi.com/docs
|
|
10
7
|
Author: Dyno Therapeutics
|
|
11
8
|
License-Expression: MIT
|
|
12
9
|
Keywords: binder-design,bioinformatics,cli,protein-design,protein-engineering,sdk,structure-prediction
|
|
@@ -31,11 +28,9 @@ Description-Content-Type: text/markdown
|
|
|
31
28
|
|
|
32
29
|
# dyno-phi
|
|
33
30
|
|
|
34
|
-
Python SDK and CLI for the [Phi](https://
|
|
31
|
+
Python SDK and CLI for the [Phi](https://dynophi.com) protein design API.
|
|
35
32
|
The `phi` package exposes synchronous (`PhiClient`) and asynchronous
|
|
36
|
-
(`AsyncPhiClient`) clients and the `phi` CLI, installed together.
|
|
37
|
-
published to PyPI from `clients/phi` in
|
|
38
|
-
[`dynotx/phi-api`](https://github.com/dynotx/phi-api).
|
|
33
|
+
(`AsyncPhiClient`) clients and the `phi` CLI, installed together.
|
|
39
34
|
|
|
40
35
|
## Install
|
|
41
36
|
|
|
@@ -48,8 +43,7 @@ uv tool install dyno-phi
|
|
|
48
43
|
`uv tool` provisions its own Python, which covers the client's **Python 3.12+**
|
|
49
44
|
requirement on stock macOS, where the system Python is 3.9. Re-run with
|
|
50
45
|
`--upgrade` to upgrade. `pip install dyno-phi` into a Python 3.12+ of your own
|
|
51
|
-
does the same.
|
|
52
|
-
form and `just install-cli-dev` installs the working tree.
|
|
46
|
+
does the same.
|
|
53
47
|
|
|
54
48
|
The SDK inside an existing project (the CLI comes with it; the `[cli]` extra
|
|
55
49
|
from 0.3.0 still installs and adds nothing):
|
|
@@ -64,8 +58,7 @@ client is first on your `PATH` (`which -a phi` lists every match) and
|
|
|
64
58
|
`pip install --upgrade dyno-phi` in the Python that owns it replaces it.
|
|
65
59
|
Coming from 0.2.x: the key is `PHI_API_KEY` (or `PHI_KEY`) and the base URL
|
|
66
60
|
`PHI_API`, the commands are `phi <group> <command>` as listed under
|
|
67
|
-
[CLI](#cli), and Python 3.12+ is required
|
|
68
|
-
[`CHANGELOG.md`](https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md).
|
|
61
|
+
[CLI](#cli), and Python 3.12+ is required.
|
|
69
62
|
|
|
70
63
|
If `uv`'s tool directory is behind another `phi` on `PATH`, sourcing uv's shell
|
|
71
64
|
shim is not enough to move it: the shim prepends the directory only when `PATH`
|
|
@@ -93,7 +86,7 @@ device. `phi auth whoami` prints who you are and which organization and
|
|
|
93
86
|
environment you are on; `phi doctor` checks the install when something is off.
|
|
94
87
|
|
|
95
88
|
An agent, CI or a service account uses an API key from
|
|
96
|
-
[
|
|
89
|
+
[app.dynophi.com](https://app.dynophi.com) instead, either saved as a profile
|
|
97
90
|
or read from the environment:
|
|
98
91
|
|
|
99
92
|
```bash
|
|
@@ -108,9 +101,9 @@ export PHI_API_KEY=ak_... # or per process
|
|
|
108
101
|
| `PHI_ORG` | Organization ID. Required with a static key. |
|
|
109
102
|
|
|
110
103
|
```bash
|
|
111
|
-
export PHI_API=https
|
|
112
|
-
export PHI_KEY=...
|
|
113
|
-
export PHI_ORG
|
|
104
|
+
export PHI_API=https://<your-deployment>
|
|
105
|
+
export PHI_KEY=... # static key
|
|
106
|
+
export PHI_ORG=<tenant> # literal static tenant, not the Clerk org
|
|
114
107
|
```
|
|
115
108
|
|
|
116
109
|
With a Clerk key (`ak_...`) the tenant comes from the key, so `PHI_ORG` is
|
|
@@ -118,7 +111,7 @@ ignored; it is required only for a static key.
|
|
|
118
111
|
|
|
119
112
|
Pass `base_url=`, `api_key=`, and `org=` to the client constructor to override
|
|
120
113
|
the environment. `api_key=` takes a sign-in's access token as readily as a key.
|
|
121
|
-
The three ways and when to use each: [
|
|
114
|
+
The three ways and when to use each: [documentation](https://dynophi.com/docs).
|
|
122
115
|
|
|
123
116
|
## 60-second quickstart
|
|
124
117
|
|
|
@@ -223,8 +216,13 @@ authored Markdown layer after the checkout's deny-list guard passes, defaults
|
|
|
223
216
|
platform documents to internal access, and skips unchanged content and access.
|
|
224
217
|
It does not delete remote-only documents.
|
|
225
218
|
|
|
219
|
+
## MCP
|
|
220
|
+
|
|
221
|
+
Phi also serves an MCP endpoint for agents at `https://api.dynophi.com/mcp`. Add it
|
|
222
|
+
to your MCP client as a remote server, or run `phi auth login`, which signs in
|
|
223
|
+
against `https://api.dynophi.com` and the same `/mcp` resource.
|
|
224
|
+
|
|
226
225
|
## Full reference
|
|
227
226
|
|
|
228
|
-
See [
|
|
229
|
-
|
|
230
|
-
reference, the error taxonomy and how a release is cut.
|
|
227
|
+
See the [documentation](https://dynophi.com/docs) for environment and profile
|
|
228
|
+
resolution, sync/async parity, the complete CLI reference and the error taxonomy.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# dyno-phi
|
|
2
2
|
|
|
3
|
-
Python SDK and CLI for the [Phi](https://
|
|
3
|
+
Python SDK and CLI for the [Phi](https://dynophi.com) protein design API.
|
|
4
4
|
The `phi` package exposes synchronous (`PhiClient`) and asynchronous
|
|
5
|
-
(`AsyncPhiClient`) clients and the `phi` CLI, installed together.
|
|
6
|
-
published to PyPI from `clients/phi` in
|
|
7
|
-
[`dynotx/phi-api`](https://github.com/dynotx/phi-api).
|
|
5
|
+
(`AsyncPhiClient`) clients and the `phi` CLI, installed together.
|
|
8
6
|
|
|
9
7
|
## Install
|
|
10
8
|
|
|
@@ -17,8 +15,7 @@ uv tool install dyno-phi
|
|
|
17
15
|
`uv tool` provisions its own Python, which covers the client's **Python 3.12+**
|
|
18
16
|
requirement on stock macOS, where the system Python is 3.9. Re-run with
|
|
19
17
|
`--upgrade` to upgrade. `pip install dyno-phi` into a Python 3.12+ of your own
|
|
20
|
-
does the same.
|
|
21
|
-
form and `just install-cli-dev` installs the working tree.
|
|
18
|
+
does the same.
|
|
22
19
|
|
|
23
20
|
The SDK inside an existing project (the CLI comes with it; the `[cli]` extra
|
|
24
21
|
from 0.3.0 still installs and adds nothing):
|
|
@@ -33,8 +30,7 @@ client is first on your `PATH` (`which -a phi` lists every match) and
|
|
|
33
30
|
`pip install --upgrade dyno-phi` in the Python that owns it replaces it.
|
|
34
31
|
Coming from 0.2.x: the key is `PHI_API_KEY` (or `PHI_KEY`) and the base URL
|
|
35
32
|
`PHI_API`, the commands are `phi <group> <command>` as listed under
|
|
36
|
-
[CLI](#cli), and Python 3.12+ is required
|
|
37
|
-
[`CHANGELOG.md`](https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md).
|
|
33
|
+
[CLI](#cli), and Python 3.12+ is required.
|
|
38
34
|
|
|
39
35
|
If `uv`'s tool directory is behind another `phi` on `PATH`, sourcing uv's shell
|
|
40
36
|
shim is not enough to move it: the shim prepends the directory only when `PATH`
|
|
@@ -62,7 +58,7 @@ device. `phi auth whoami` prints who you are and which organization and
|
|
|
62
58
|
environment you are on; `phi doctor` checks the install when something is off.
|
|
63
59
|
|
|
64
60
|
An agent, CI or a service account uses an API key from
|
|
65
|
-
[
|
|
61
|
+
[app.dynophi.com](https://app.dynophi.com) instead, either saved as a profile
|
|
66
62
|
or read from the environment:
|
|
67
63
|
|
|
68
64
|
```bash
|
|
@@ -77,9 +73,9 @@ export PHI_API_KEY=ak_... # or per process
|
|
|
77
73
|
| `PHI_ORG` | Organization ID. Required with a static key. |
|
|
78
74
|
|
|
79
75
|
```bash
|
|
80
|
-
export PHI_API=https
|
|
81
|
-
export PHI_KEY=...
|
|
82
|
-
export PHI_ORG
|
|
76
|
+
export PHI_API=https://<your-deployment>
|
|
77
|
+
export PHI_KEY=... # static key
|
|
78
|
+
export PHI_ORG=<tenant> # literal static tenant, not the Clerk org
|
|
83
79
|
```
|
|
84
80
|
|
|
85
81
|
With a Clerk key (`ak_...`) the tenant comes from the key, so `PHI_ORG` is
|
|
@@ -87,7 +83,7 @@ ignored; it is required only for a static key.
|
|
|
87
83
|
|
|
88
84
|
Pass `base_url=`, `api_key=`, and `org=` to the client constructor to override
|
|
89
85
|
the environment. `api_key=` takes a sign-in's access token as readily as a key.
|
|
90
|
-
The three ways and when to use each: [
|
|
86
|
+
The three ways and when to use each: [documentation](https://dynophi.com/docs).
|
|
91
87
|
|
|
92
88
|
## 60-second quickstart
|
|
93
89
|
|
|
@@ -192,8 +188,13 @@ authored Markdown layer after the checkout's deny-list guard passes, defaults
|
|
|
192
188
|
platform documents to internal access, and skips unchanged content and access.
|
|
193
189
|
It does not delete remote-only documents.
|
|
194
190
|
|
|
191
|
+
## MCP
|
|
192
|
+
|
|
193
|
+
Phi also serves an MCP endpoint for agents at `https://api.dynophi.com/mcp`. Add it
|
|
194
|
+
to your MCP client as a remote server, or run `phi auth login`, which signs in
|
|
195
|
+
against `https://api.dynophi.com` and the same `/mcp` resource.
|
|
196
|
+
|
|
195
197
|
## Full reference
|
|
196
198
|
|
|
197
|
-
See [
|
|
198
|
-
|
|
199
|
-
reference, the error taxonomy and how a release is cut.
|
|
199
|
+
See the [documentation](https://dynophi.com/docs) for environment and profile
|
|
200
|
+
resolution, sync/async parity, the complete CLI reference and the error taxonomy.
|
|
@@ -49,11 +49,8 @@ cli = []
|
|
|
49
49
|
phi = "phi.cli:main"
|
|
50
50
|
|
|
51
51
|
[project.urls]
|
|
52
|
-
Homepage = "https://
|
|
53
|
-
Documentation = "https://
|
|
54
|
-
Source = "https://github.com/dynotx/phi-api/tree/main/clients/phi"
|
|
55
|
-
Changelog = "https://github.com/dynotx/phi-api/blob/main/clients/phi/CHANGELOG.md"
|
|
56
|
-
Issues = "https://github.com/dynotx/phi-api/issues"
|
|
52
|
+
Homepage = "https://dynophi.com"
|
|
53
|
+
Documentation = "https://dynophi.com/docs"
|
|
57
54
|
|
|
58
55
|
[dependency-groups]
|
|
59
56
|
dev = [
|
|
@@ -73,7 +70,7 @@ path = "src/phi/_version.py"
|
|
|
73
70
|
packages = ["src/phi"]
|
|
74
71
|
|
|
75
72
|
[tool.hatch.build.targets.sdist]
|
|
76
|
-
include = ["src/phi", "
|
|
73
|
+
include = ["src/phi", "examples", "README.md", "pyproject.toml"]
|
|
77
74
|
|
|
78
75
|
[tool.ruff]
|
|
79
76
|
line-length = 100
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.4.0"
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
+
import httpx
|
|
7
8
|
import typer
|
|
8
9
|
|
|
9
10
|
from phi import config, oauth, profiles
|
|
@@ -19,8 +20,7 @@ from ..state import USER_AGENT, CliState
|
|
|
19
20
|
app = typer.Typer(no_args_is_help=True, help="Sign in and inspect the active identity.")
|
|
20
21
|
|
|
21
22
|
PRESETS = {
|
|
22
|
-
"hosted": "https://
|
|
23
|
-
"staging": "https://phi-api-staging-917387676927.us-central1.run.app",
|
|
23
|
+
"hosted": "https://api.dynophi.com",
|
|
24
24
|
"local": "http://localhost:8080",
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -109,11 +109,23 @@ def login(
|
|
|
109
109
|
say = _say(state)
|
|
110
110
|
say("Phi")
|
|
111
111
|
say(f"Signing in to {base_url}")
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
try:
|
|
113
|
+
with oauth.http_client() as http:
|
|
114
|
+
if device:
|
|
115
|
+
tokens, server = oauth.sign_in_with_device_code(base_url, http=http, say=say)
|
|
116
|
+
else:
|
|
117
|
+
tokens, server = oauth.sign_in_with_browser(base_url, http=http, say=say)
|
|
118
|
+
except oauth.OAuthError as exc:
|
|
119
|
+
if (
|
|
120
|
+
api is None
|
|
121
|
+
and config.classify_environment(base_url) == "unknown"
|
|
122
|
+
and isinstance(exc.__cause__, httpx.RequestError)
|
|
123
|
+
):
|
|
124
|
+
raise oauth.OAuthError(
|
|
125
|
+
f"{exc}; if profile '{name}' was saved by an earlier release, "
|
|
126
|
+
f"run phi auth login --api {PRESETS['hosted']}"
|
|
127
|
+
) from exc
|
|
128
|
+
raise
|
|
117
129
|
cred = OAuthCredential.from_tokens(
|
|
118
130
|
name, tokens, server, client_id=oauth.client_id_for(base_url)
|
|
119
131
|
)
|
|
@@ -58,7 +58,12 @@ def check_base_url(base_url: str) -> Check:
|
|
|
58
58
|
f"{base_url} answered {exc.response.status_code} on /readyz",
|
|
59
59
|
)
|
|
60
60
|
except (httpx.HTTPError, ValueError) as exc:
|
|
61
|
-
hint =
|
|
61
|
+
hint = ""
|
|
62
|
+
if environment == "unknown":
|
|
63
|
+
hint = (
|
|
64
|
+
f" ({source} names it); if this profile was saved by an earlier release, "
|
|
65
|
+
f"run phi auth login --api {config.DEFAULT_BASE_URL}"
|
|
66
|
+
)
|
|
62
67
|
return Check("api", False, f"{base_url} is not reachable: {exc}{hint}")
|
|
63
68
|
if environment == "unknown":
|
|
64
69
|
return Check(
|
|
@@ -52,6 +52,7 @@ def show(
|
|
|
52
52
|
if state.json_output:
|
|
53
53
|
render.print_json(schema.model_dump())
|
|
54
54
|
return
|
|
55
|
+
render.kv_panel(overview(schema), title=schema.job_type, no_color=state.no_color)
|
|
55
56
|
_render_schema(schema.params_schema, "Parameters", state.no_color)
|
|
56
57
|
_render_schema(schema.inputs_schema, "Inputs", state.no_color)
|
|
57
58
|
|
|
@@ -80,7 +81,46 @@ def format_typical(seconds: int | None) -> str:
|
|
|
80
81
|
return f"about {max(1, round(seconds / 60))} min"
|
|
81
82
|
|
|
82
83
|
|
|
84
|
+
def overview(schema: JobTypeSchema) -> dict[str, str]:
|
|
85
|
+
"""What to know before submitting: purpose, price, availability, limits, usual wall time."""
|
|
86
|
+
rows: dict[str, str] = {}
|
|
87
|
+
if schema.purpose:
|
|
88
|
+
rows["purpose"] = schema.purpose
|
|
89
|
+
price = f"{schema.credit_cost} credits at the default params"
|
|
90
|
+
if schema.catalog_price is not None:
|
|
91
|
+
basket = schema.catalog_price
|
|
92
|
+
price += f"; {basket.credits} for {basket.count} {basket.unit}"
|
|
93
|
+
rows["price"] = price + " (POST /v1/jobs/estimate quotes a request)"
|
|
94
|
+
if schema.available:
|
|
95
|
+
rows["available"] = "yes"
|
|
96
|
+
else:
|
|
97
|
+
rows["available"] = f"no, {schema.gate_reason or 'withheld on this deployment'}"
|
|
98
|
+
rows["environments"] = ", ".join(schema.environments)
|
|
99
|
+
limits = _limits(schema)
|
|
100
|
+
if limits:
|
|
101
|
+
rows["limits"] = limits
|
|
102
|
+
if schema.typical_seconds is not None:
|
|
103
|
+
rows["typical time"] = format_typical(schema.typical_seconds)
|
|
104
|
+
if schema.notes:
|
|
105
|
+
rows["notes"] = schema.notes
|
|
106
|
+
return rows
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _limits(schema: JobTypeSchema) -> str:
|
|
110
|
+
constraints = schema.input_constraints
|
|
111
|
+
parts: list[str] = []
|
|
112
|
+
if constraints.max_chains is not None:
|
|
113
|
+
parts.append(f"at most {constraints.max_chains} chain(s)")
|
|
114
|
+
if constraints.max_length is not None:
|
|
115
|
+
parts.append(f"at most {constraints.max_length} residues per sequence")
|
|
116
|
+
if constraints.accepts_ligands is not None:
|
|
117
|
+
parts.append("ligands accepted" if constraints.accepts_ligands else "no ligands")
|
|
118
|
+
return "; ".join(parts)
|
|
119
|
+
|
|
120
|
+
|
|
83
121
|
def _summary(schema: JobTypeSchema) -> str:
|
|
122
|
+
if schema.purpose:
|
|
123
|
+
return schema.purpose
|
|
84
124
|
description = schema.params_schema.get("description")
|
|
85
125
|
if isinstance(description, str) and description:
|
|
86
126
|
return description.splitlines()[0]
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"""`phi skills`: the skills Phi publishes, listed, shown and installed where agents read them.
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
The site serves the index at /skills.json and each skill as Markdown. `install` prefers
|
|
4
|
+
the `skills` installer (`npx skills add`), which puts a skill where every agent on the
|
|
5
|
+
machine looks and keeps a lock file; without `npx` it writes the Markdown itself into
|
|
6
|
+
the agents' skill directories, so a machine with only `pip install dyno-phi` and HTTPS
|
|
7
|
+
still gets them.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from __future__ import annotations
|
|
@@ -26,7 +26,7 @@ from ..state import CliState
|
|
|
26
26
|
|
|
27
27
|
app = typer.Typer(no_args_is_help=True, help="Phi's agent skills: list, show, install.")
|
|
28
28
|
|
|
29
|
-
DEFAULT_INDEX_URL = "https://
|
|
29
|
+
DEFAULT_INDEX_URL = "https://dynophi.com/skills.json"
|
|
30
30
|
INDEX_ENV = "PHI_SKILLS_INDEX"
|
|
31
31
|
FETCH_TIMEOUT = 20.0
|
|
32
32
|
|
|
@@ -121,7 +121,7 @@ def npx_path() -> str | None:
|
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
def run_installer(index: Index, names: list[str], *, global_: bool, agents: list[str]) -> int:
|
|
124
|
-
"""`npx skills add
|
|
124
|
+
"""`npx skills add <repo> [--skill name]... [-g] [-a agent]... -y`, <repo> from the index."""
|
|
125
125
|
command = ["npx", "-y", "skills", "add", index.repo]
|
|
126
126
|
for name in names:
|
|
127
127
|
command += ["--skill", name]
|
|
@@ -171,27 +171,50 @@ def installed_skills(*, cwd: Path | None = None) -> dict[str, list[str]]:
|
|
|
171
171
|
return found
|
|
172
172
|
|
|
173
173
|
|
|
174
|
+
def installed_names() -> set[str]:
|
|
175
|
+
"""Every skill name sitting in an agent's project or global directory."""
|
|
176
|
+
return {name for names in installed_skills().values() for name in names}
|
|
177
|
+
|
|
178
|
+
|
|
174
179
|
@app.command("list")
|
|
175
180
|
def list_(ctx: typer.Context) -> None:
|
|
176
|
-
"""The skills Phi publishes,
|
|
181
|
+
"""The skills Phi publishes, their versions, and which are installed for your agents."""
|
|
177
182
|
state: CliState = ctx.obj
|
|
178
183
|
index = read_index()
|
|
184
|
+
installed = installed_names()
|
|
179
185
|
if state.json_output:
|
|
180
186
|
render.print_json(
|
|
181
187
|
{
|
|
182
188
|
"repo": index.repo,
|
|
183
189
|
"install": index.install,
|
|
184
|
-
"skills": [
|
|
190
|
+
"skills": [
|
|
191
|
+
{**skill.__dict__, "installed": skill.name in installed}
|
|
192
|
+
for skill in index.skills
|
|
193
|
+
],
|
|
185
194
|
}
|
|
186
195
|
)
|
|
187
196
|
return
|
|
188
197
|
render.table(
|
|
189
|
-
["name", "version", "description"],
|
|
190
|
-
[
|
|
198
|
+
["name", "version", "installed", "description"],
|
|
199
|
+
[
|
|
200
|
+
[
|
|
201
|
+
skill.name,
|
|
202
|
+
skill.version,
|
|
203
|
+
"yes" if skill.name in installed else "no",
|
|
204
|
+
skill.description.split(". ")[0],
|
|
205
|
+
]
|
|
206
|
+
for skill in index.skills
|
|
207
|
+
],
|
|
191
208
|
no_color=state.no_color,
|
|
192
209
|
)
|
|
193
210
|
printer = render.console(no_color=state.no_color)
|
|
194
|
-
printer.print(
|
|
211
|
+
printer.print(
|
|
212
|
+
"\n`installed` means the skill is in this project's or your home Claude Code, Cursor "
|
|
213
|
+
"or Codex skills directory.",
|
|
214
|
+
markup=False,
|
|
215
|
+
highlight=False,
|
|
216
|
+
)
|
|
217
|
+
printer.print(f"Install every one: {index.install}", markup=False, highlight=False)
|
|
195
218
|
printer.print("Or: phi skills install [name]...", markup=False, highlight=False)
|
|
196
219
|
|
|
197
220
|
|
|
@@ -57,7 +57,7 @@ def prepare_sync(
|
|
|
57
57
|
if guard.is_file():
|
|
58
58
|
_run_guard(root, guard)
|
|
59
59
|
else:
|
|
60
|
-
# A checkout with no deny-list guard is a public one
|
|
60
|
+
# A checkout with no deny-list guard is a public one: every document
|
|
61
61
|
# it publishes says so itself with `access: general` in its frontmatter, or nothing goes.
|
|
62
62
|
undeclared = [
|
|
63
63
|
document.name
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
from dataclasses import dataclass, replace
|
|
5
5
|
from datetime import UTC, datetime
|
|
6
6
|
from pathlib import Path
|
|
7
|
+
from urllib.parse import urlparse
|
|
7
8
|
|
|
8
9
|
import httpx
|
|
9
10
|
|
|
@@ -11,7 +12,7 @@ from . import oauth, profiles
|
|
|
11
12
|
from .errors import PhiConfigError
|
|
12
13
|
from .oauth import PhiSignedOutError, TokenSet
|
|
13
14
|
|
|
14
|
-
DEFAULT_BASE_URL = "https://
|
|
15
|
+
DEFAULT_BASE_URL = "https://api.dynophi.com"
|
|
15
16
|
CONFIG_PATH = Path.home() / ".config" / "phi" / "config.toml"
|
|
16
17
|
|
|
17
18
|
SIGNED_OUT = "Signed out. Run phi auth login."
|
|
@@ -31,11 +32,12 @@ ENVIRONMENT_NAMES = {"hosted": "production", "staging": "staging", "local": "dev
|
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def classify_environment(base_url: str) -> str:
|
|
34
|
-
|
|
35
|
+
host = urlparse(base_url).hostname or ""
|
|
36
|
+
if host == urlparse(DEFAULT_BASE_URL).hostname:
|
|
35
37
|
return "hosted"
|
|
36
|
-
if "
|
|
38
|
+
if "staging" in host:
|
|
37
39
|
return "staging"
|
|
38
|
-
if "localhost"
|
|
40
|
+
if host in ("localhost", "127.0.0.1"):
|
|
39
41
|
return "local"
|
|
40
42
|
return "unknown"
|
|
41
43
|
|
|
@@ -83,7 +83,7 @@ _TOOL_REGISTRY: dict[str, _ToolSpec] = {
|
|
|
83
83
|
"genie3": _ToolSpec("GENIE3", _NO_PORTS, _BACKBONES_OUT),
|
|
84
84
|
"boltz": _ToolSpec("BOLTZ", _SEQUENCES_IN, _FOLD_OUT),
|
|
85
85
|
"boltz2": _ToolSpec("BOLTZ2", _NO_PORTS, _FOLD_OUT),
|
|
86
|
-
"
|
|
86
|
+
"dynopsi": _ToolSpec("DYNOPSI", _NO_PORTS, _BACKBONES_OUT),
|
|
87
87
|
"dynopsi_dev": _ToolSpec("DYNOPSI_DEV", _NO_PORTS, _BACKBONES_OUT),
|
|
88
88
|
"boltzgen": _ToolSpec("BOLTZGEN", _NO_PORTS, _NO_PORTS, typed_ports=False),
|
|
89
89
|
# Terminal co-design like the monolithic boltzgen stage: no typed ports yet.
|
|
@@ -16,21 +16,25 @@ JobType = Literal[
|
|
|
16
16
|
"BOLTZGEN_DESIGN_ONLY",
|
|
17
17
|
"BOLTZGEN_FULL",
|
|
18
18
|
"CAPSID_FOLD_ESMFOLD2",
|
|
19
|
+
"CAPSID_FOLD_OPENFOLD3",
|
|
19
20
|
"CHAI1",
|
|
20
21
|
"DOCKQ",
|
|
21
|
-
"
|
|
22
|
+
"DYNOPSI",
|
|
22
23
|
"DYNOPSI_DEV",
|
|
23
24
|
"ESMC",
|
|
24
25
|
"ESMFOLD",
|
|
25
26
|
"ESMFOLD2",
|
|
26
27
|
"ESMFOLD2_FAST",
|
|
27
28
|
"ESM_IF1",
|
|
29
|
+
"EVO2",
|
|
30
|
+
"EVO2_GENERATE",
|
|
28
31
|
"FOLD_AND_SCORE_NOVELTY",
|
|
29
32
|
"FREE_BINDCRAFT",
|
|
30
33
|
"GENIE3",
|
|
31
34
|
"GERMINAL",
|
|
32
35
|
"LACUNA",
|
|
33
36
|
"MASIF_SITE",
|
|
37
|
+
"MOL1",
|
|
34
38
|
"MSA_PAIRFORMER",
|
|
35
39
|
"OPENDDE",
|
|
36
40
|
"OPENFOLD3",
|
|
@@ -5,7 +5,7 @@ from typing import Any
|
|
|
5
5
|
from pydantic import Field
|
|
6
6
|
|
|
7
7
|
from .common import PhiModel
|
|
8
|
-
from .runs import StagePricing
|
|
8
|
+
from .runs import CatalogPrice, StagePricing
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class InputConstraints(PhiModel):
|
|
@@ -17,6 +17,8 @@ class InputConstraints(PhiModel):
|
|
|
17
17
|
class JobTypeSchema(PhiModel):
|
|
18
18
|
job_type: str
|
|
19
19
|
credit_cost: int
|
|
20
|
+
catalog_price: CatalogPrice | None = None
|
|
21
|
+
rate_revision: str | None = None
|
|
20
22
|
pricing: list[StagePricing] = Field(default_factory=list)
|
|
21
23
|
params_schema: dict[str, Any]
|
|
22
24
|
inputs_schema: dict[str, Any]
|
|
@@ -25,3 +27,5 @@ class JobTypeSchema(PhiModel):
|
|
|
25
27
|
environments: list[str]
|
|
26
28
|
input_constraints: InputConstraints
|
|
27
29
|
typical_seconds: int | None = None
|
|
30
|
+
purpose: str | None = None
|
|
31
|
+
notes: str | None = None
|
|
@@ -52,11 +52,19 @@ class QuoteLine(PhiModel):
|
|
|
52
52
|
class StagePricing(PhiModel):
|
|
53
53
|
stage: str
|
|
54
54
|
unit: str
|
|
55
|
-
|
|
55
|
+
cents: int
|
|
56
56
|
cap: int | None = None
|
|
57
57
|
gpu: str
|
|
58
|
-
startup_minutes: int = 0
|
|
59
58
|
per: int = 1
|
|
59
|
+
included: int = 0
|
|
60
|
+
start_cents: int = 0
|
|
61
|
+
basket: int = 1
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class CatalogPrice(PhiModel):
|
|
65
|
+
credits: int
|
|
66
|
+
count: int
|
|
67
|
+
unit: str
|
|
60
68
|
|
|
61
69
|
|
|
62
70
|
class RunEstimate(BaseModel):
|
|
@@ -150,6 +158,8 @@ class RunTimelineResponse(PhiModel):
|
|
|
150
158
|
class PipelineTypeResponse(PhiModel):
|
|
151
159
|
pipeline_type: str
|
|
152
160
|
credit_cost: int
|
|
161
|
+
catalog_price: CatalogPrice | None = None
|
|
162
|
+
rate_revision: str | None = None
|
|
153
163
|
pricing: list[StagePricing] = Field(default_factory=list)
|
|
154
164
|
available_as_job: bool
|
|
155
165
|
default_params: dict[str, Any]
|
|
@@ -490,7 +490,7 @@ def device_authorization(
|
|
|
490
490
|
if not server.device_authorization_endpoint:
|
|
491
491
|
raise OAuthError(
|
|
492
492
|
f"{server.issuer} offers no device authorization; on a machine without a "
|
|
493
|
-
"browser, run phi auth login --key with an API key from
|
|
493
|
+
"browser, run phi auth login --key with an API key from dynophi.com."
|
|
494
494
|
)
|
|
495
495
|
try:
|
|
496
496
|
response = http.post(
|