commoncompute 0.2.0__tar.gz → 0.3.1__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.
- {commoncompute-0.2.0 → commoncompute-0.3.1}/.gitignore +1 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/LICENSE +1 -1
- {commoncompute-0.2.0 → commoncompute-0.3.1}/PKG-INFO +90 -70
- {commoncompute-0.2.0 → commoncompute-0.3.1}/README.md +88 -68
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/__init__.py +7 -14
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/_async_client.py +3 -1
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/_config.py +3 -2
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/_generated_workloads.py +7 -4
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/_transport.py +2 -2
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/aws_batch.py +5 -6
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/cli.py +59 -19
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/client.py +19 -1
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/connect.py +2 -1
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/tasks.py +27 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/pyproject.toml +6 -2
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/_async_tasks.py +0 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/compat/__init__.py +0 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/compat/openai.py +0 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/errors.py +0 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/models.py +0 -0
- {commoncompute-0.2.0 → commoncompute-0.3.1}/commoncompute/py.typed +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: commoncompute
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Official Python SDK for Common Compute — the batch AI bill you shouldn't be paying.
|
|
5
5
|
Project-URL: Homepage, https://commoncompute.ai
|
|
6
6
|
Project-URL: Documentation, https://commoncompute.ai/docs
|
|
7
|
-
Project-URL: Source, https://github.com/
|
|
7
|
+
Project-URL: Source, https://github.com/commoncompute/sdk
|
|
8
8
|
Project-URL: Changelog, https://commoncompute.ai/changelog
|
|
9
9
|
Author-email: Common Compute <support@commoncompute.ai>
|
|
10
10
|
License: MIT
|
|
@@ -44,11 +44,14 @@ for **successful** jobs — each with a verifiable receipt.
|
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
46
|
pip install commoncompute # core: httpx + pydantic only
|
|
47
|
-
pip install "commoncompute[cli]" # + the `
|
|
48
|
-
|
|
47
|
+
pip install "commoncompute[cli]" # + the `commoncompute` command line
|
|
48
|
+
commoncompute login # opens the browser — no key to copy-paste
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
The command is `commoncompute`. A short `cc` is **not** installed — that name
|
|
52
|
+
belongs to the system C compiler. Want the shorthand? `alias cc="commoncompute"`.
|
|
53
|
+
|
|
54
|
+
`commoncompute login` (or `commoncompute.connect()` from a script or notebook) opens an
|
|
52
55
|
approval page in your browser; click **Approve** and a fresh API key is saved
|
|
53
56
|
to `~/.config/commoncompute/credentials`, where the SDK finds it automatically.
|
|
54
57
|
Prefer explicit config? `export CC_API_KEY=cc_live_...` works everywhere and
|
|
@@ -61,7 +64,8 @@ import commoncompute as cc
|
|
|
61
64
|
|
|
62
65
|
client = cc.Client() # reads CC_API_KEY, or the saved credentials file
|
|
63
66
|
|
|
64
|
-
job = client.
|
|
67
|
+
job = client.submit("coreml_embed", {"input": ["what is the neural engine?"]},
|
|
68
|
+
model_id="bge-base")
|
|
65
69
|
print(job.job_id, job.locked_price_usd, job.eta_seconds) # price known BEFORE it runs
|
|
66
70
|
|
|
67
71
|
result = client.result(job) # waits, downloads, attaches the receipt
|
|
@@ -69,7 +73,10 @@ print(result.output)
|
|
|
69
73
|
print(result.receipt) # signed proof of what ran, where, for how much
|
|
70
74
|
```
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
Prefer the OpenAI-style surface? `client.embeddings.create(input=[...],
|
|
77
|
+
model="bge-base")` returns vectors synchronously.
|
|
78
|
+
|
|
79
|
+
## Examples — live today
|
|
73
80
|
|
|
74
81
|
### 1. OCR / document extraction — vs AWS Textract
|
|
75
82
|
|
|
@@ -78,38 +85,40 @@ job = client.ocr.extract("https://example.com/contracts.pdf", structured=True)
|
|
|
78
85
|
result = client.result(job) # blocks + bounding boxes as JSON
|
|
79
86
|
```
|
|
80
87
|
|
|
81
|
-
### 2.
|
|
88
|
+
### 2. Embeddings in bulk
|
|
82
89
|
|
|
83
90
|
```python
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
for result in client.submit_many(
|
|
92
|
+
"coreml_embed",
|
|
93
|
+
[{"input": chunked(doc)} for doc in corpus],
|
|
87
94
|
max_concurrent=16,
|
|
88
|
-
)
|
|
95
|
+
):
|
|
96
|
+
save(result.output) # results stream as they complete
|
|
89
97
|
```
|
|
90
98
|
|
|
91
|
-
### 3.
|
|
99
|
+
### 3. Background removal
|
|
92
100
|
|
|
93
101
|
```python
|
|
94
|
-
job = client.
|
|
95
|
-
top = client.result(job).output
|
|
102
|
+
job = client.images.remove_background("product-shot.png")
|
|
96
103
|
```
|
|
97
104
|
|
|
98
|
-
|
|
105
|
+
Also live: speech synthesis, image classification/detection/pose, barcode
|
|
106
|
+
reading, HEIC conversion — plus the generic `client.submit(workload_id,
|
|
107
|
+
payload)` for anything marked **live** in
|
|
108
|
+
[the catalog](https://commoncompute.ai/workloads).
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
job = client.translate(catalog_descriptions, target_lang="de")
|
|
102
|
-
```
|
|
110
|
+
### In preview
|
|
103
111
|
|
|
104
|
-
|
|
112
|
+
`client.translate(...)` and `client.video.transcode(...)` run on preview
|
|
113
|
+
capacity — functional, not yet GA.
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
job = client.images.remove_background("product-shot.png")
|
|
108
|
-
```
|
|
115
|
+
### Not live yet
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
`client.
|
|
112
|
-
|
|
117
|
+
`client.transcription.*`, `client.rerank(...)`, `client.images.generate(...)`,
|
|
118
|
+
`client.chat.*`, and `client.build.ios_test(...)` target workloads still
|
|
119
|
+
marked *coming soon*: the API refuses them with a clear
|
|
120
|
+
`workload_not_available` error (HTTP 409) rather than queueing a job that
|
|
121
|
+
won't run. They activate automatically as those lanes go live — watch
|
|
113
122
|
[the catalog](https://commoncompute.ai/workloads).
|
|
114
123
|
|
|
115
124
|
## Price before execution, hard caps, dry runs
|
|
@@ -183,48 +192,59 @@ raw request/response dicts instead of typed `Job`/`TaskResult` objects.
|
|
|
183
192
|
|
|
184
193
|
## CLI
|
|
185
194
|
|
|
186
|
-
`pip install "commoncompute[cli]"` installs the `
|
|
195
|
+
`pip install "commoncompute[cli]"` installs the `commoncompute` command.
|
|
196
|
+
|
|
197
|
+
> **Why not a short `cc`?** Because `cc` is the Unix C compiler
|
|
198
|
+
> (`/usr/bin/cc`). Shipping a binary by that name puts it ahead of the real
|
|
199
|
+
> compiler on `PATH` for anyone whose Python bin directory sorts first, and
|
|
200
|
+
> every build that shells out to `cc` then fails with a CLI usage error
|
|
201
|
+
> instead of compiling. So `commoncompute` is the only command installed. If
|
|
202
|
+
> you want the shorthand, opt in yourself:
|
|
203
|
+
>
|
|
204
|
+
> ```bash
|
|
205
|
+
> alias cc="commoncompute" # add to ~/.zshrc or ~/.bashrc
|
|
206
|
+
> ```
|
|
187
207
|
|
|
188
208
|
```bash
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
209
|
+
commoncompute login # stores the key locally
|
|
210
|
+
commoncompute quote vision_ocr --units 5 # price + ETA, no execution
|
|
211
|
+
commoncompute submit coreml_embed --payload '{"input":["hi"]}' --wait
|
|
212
|
+
commoncompute jobs list
|
|
213
|
+
commoncompute jobs get <id>
|
|
214
|
+
commoncompute balance
|
|
215
|
+
commoncompute receipts export --format csv --out receipts.csv
|
|
196
216
|
```
|
|
197
217
|
|
|
198
218
|
### Commands
|
|
199
219
|
|
|
200
220
|
| Command | What it does |
|
|
201
221
|
|---------|--------------|
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `
|
|
212
|
-
| `
|
|
213
|
-
| `
|
|
214
|
-
| `
|
|
215
|
-
| `
|
|
216
|
-
| `
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
| `
|
|
226
|
-
|
|
227
|
-
`
|
|
222
|
+
| `commoncompute login` / `commoncompute logout` | Store / remove the API key (browser approval, or `--api-key`) |
|
|
223
|
+
| `commoncompute whoami` | Show the account behind the current key |
|
|
224
|
+
| `commoncompute balance` | Current workspace balance |
|
|
225
|
+
| `commoncompute usage` | Spend + call-count rollups over a date range (`--start`, `--end`, `--group-by`) |
|
|
226
|
+
| `commoncompute spend` | Total spend over the last `--days` N, grouped by workload |
|
|
227
|
+
| `commoncompute tier` | Current volume tier and the next threshold |
|
|
228
|
+
| `commoncompute workloads` | List available workloads |
|
|
229
|
+
| `commoncompute models` | List models (`--workload` to filter) |
|
|
230
|
+
| `commoncompute quote` | Price + ETA for a workload without submitting (`--units`, `--priority`, `--model`) |
|
|
231
|
+
| `commoncompute submit` | Submit one job (`--payload/-f`, `--model`, `--priority`, `--wait`, `--timeout`) |
|
|
232
|
+
| `commoncompute submit-many` | Submit a JSONL file of payloads; stream one result per line as NDJSON (`--input/-i`, `--max-concurrent`, `--no-wait`) |
|
|
233
|
+
| `commoncompute chat` | One-shot chat message to a model (`--model`, `--stream/--no-stream`) |
|
|
234
|
+
| `commoncompute embed` | Embed a single string (prints the vector length) |
|
|
235
|
+
| `commoncompute playground` | Open the web playground |
|
|
236
|
+
| `commoncompute jobs list` | Recent submissions, newest first (`--limit/-n`) |
|
|
237
|
+
| `commoncompute jobs get <id>` | Fetch one job |
|
|
238
|
+
| `commoncompute jobs wait <id>` | Poll a job to a terminal state (`--timeout/-t`) |
|
|
239
|
+
| `commoncompute jobs events <id>` | Event timeline for a job |
|
|
240
|
+
| `commoncompute jobs download <id>` | Download a job's result (`--out/-o`, else stdout) |
|
|
241
|
+
| `commoncompute keys list` / `create` / `revoke` | Manage API keys |
|
|
242
|
+
| `commoncompute receipts list` | Receipts for completed jobs (`--limit/-n`) |
|
|
243
|
+
| `commoncompute receipts get <id>` | Signed receipt for a single job |
|
|
244
|
+
| `commoncompute receipts export` | Export receipts as CSV or JSON (`--format/-f`, `--out/-o`, `--limit/-n`) |
|
|
245
|
+
| `commoncompute config path` / `show` / `set` / `unset` | Inspect and edit local settings (see below) |
|
|
246
|
+
|
|
247
|
+
`commoncompute --version` (or `-V`) prints the version. Every read command that renders a
|
|
228
248
|
table also accepts **`--json`** for plain, ANSI-free machine-readable output —
|
|
229
249
|
`whoami`, `balance`, `usage`, `spend`, `tier`, `workloads`, `models`, `quote`,
|
|
230
250
|
`submit`, `jobs list/get/wait/events`, `keys list`, and `receipts list`.
|
|
@@ -234,20 +254,20 @@ table also accepts **`--json`** for plain, ANSI-free machine-readable output —
|
|
|
234
254
|
Typer ships completion for bash, zsh, fish, and PowerShell:
|
|
235
255
|
|
|
236
256
|
```bash
|
|
237
|
-
|
|
238
|
-
|
|
257
|
+
commoncompute --install-completion # install for the current shell
|
|
258
|
+
commoncompute --show-completion # print the script to inspect or customise
|
|
239
259
|
```
|
|
240
260
|
|
|
241
261
|
### Exit codes
|
|
242
262
|
|
|
243
|
-
Scripts can branch on `
|
|
263
|
+
Scripts can branch on `commoncompute`'s exit status:
|
|
244
264
|
|
|
245
265
|
| Code | Meaning |
|
|
246
266
|
|------|---------|
|
|
247
267
|
| `0` | Success |
|
|
248
268
|
| `1` | API or runtime error (network, server, bad request) |
|
|
249
269
|
| `2` | Usage error — missing/invalid arguments, or no credentials found |
|
|
250
|
-
| `3` | The job reached a **failed** terminal state (`failed` / `dead_letter` / `cancelled`) — `
|
|
270
|
+
| `3` | The job reached a **failed** terminal state (`failed` / `dead_letter` / `cancelled`) — `commoncompute jobs wait` and `commoncompute submit --wait` only |
|
|
251
271
|
|
|
252
272
|
## Migrating from OpenAI (optional)
|
|
253
273
|
|
|
@@ -316,14 +336,14 @@ Environment variables take precedence over both files at runtime:
|
|
|
316
336
|
Inspect and edit the local config from the CLI:
|
|
317
337
|
|
|
318
338
|
```bash
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
339
|
+
commoncompute config path # print the config directory
|
|
340
|
+
commoncompute config show # settings + active credential source (key masked)
|
|
341
|
+
commoncompute config set base_url https://api.commoncompute.ai
|
|
342
|
+
commoncompute config set org my-workspace
|
|
343
|
+
commoncompute config unset org
|
|
324
344
|
```
|
|
325
345
|
|
|
326
|
-
Env vars still win at runtime — `
|
|
346
|
+
Env vars still win at runtime — `commoncompute config set` writes the file, but
|
|
327
347
|
`CC_BASE_URL` / `CC_ORG` override it for a given process.
|
|
328
348
|
|
|
329
349
|
Python 3.9+. Core dependencies: `httpx`, `pydantic`. MIT license.
|
|
@@ -9,11 +9,14 @@ for **successful** jobs — each with a verifiable receipt.
|
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
pip install commoncompute # core: httpx + pydantic only
|
|
12
|
-
pip install "commoncompute[cli]" # + the `
|
|
13
|
-
|
|
12
|
+
pip install "commoncompute[cli]" # + the `commoncompute` command line
|
|
13
|
+
commoncompute login # opens the browser — no key to copy-paste
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
The command is `commoncompute`. A short `cc` is **not** installed — that name
|
|
17
|
+
belongs to the system C compiler. Want the shorthand? `alias cc="commoncompute"`.
|
|
18
|
+
|
|
19
|
+
`commoncompute login` (or `commoncompute.connect()` from a script or notebook) opens an
|
|
17
20
|
approval page in your browser; click **Approve** and a fresh API key is saved
|
|
18
21
|
to `~/.config/commoncompute/credentials`, where the SDK finds it automatically.
|
|
19
22
|
Prefer explicit config? `export CC_API_KEY=cc_live_...` works everywhere and
|
|
@@ -26,7 +29,8 @@ import commoncompute as cc
|
|
|
26
29
|
|
|
27
30
|
client = cc.Client() # reads CC_API_KEY, or the saved credentials file
|
|
28
31
|
|
|
29
|
-
job = client.
|
|
32
|
+
job = client.submit("coreml_embed", {"input": ["what is the neural engine?"]},
|
|
33
|
+
model_id="bge-base")
|
|
30
34
|
print(job.job_id, job.locked_price_usd, job.eta_seconds) # price known BEFORE it runs
|
|
31
35
|
|
|
32
36
|
result = client.result(job) # waits, downloads, attaches the receipt
|
|
@@ -34,7 +38,10 @@ print(result.output)
|
|
|
34
38
|
print(result.receipt) # signed proof of what ran, where, for how much
|
|
35
39
|
```
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
Prefer the OpenAI-style surface? `client.embeddings.create(input=[...],
|
|
42
|
+
model="bge-base")` returns vectors synchronously.
|
|
43
|
+
|
|
44
|
+
## Examples — live today
|
|
38
45
|
|
|
39
46
|
### 1. OCR / document extraction — vs AWS Textract
|
|
40
47
|
|
|
@@ -43,38 +50,40 @@ job = client.ocr.extract("https://example.com/contracts.pdf", structured=True)
|
|
|
43
50
|
result = client.result(job) # blocks + bounding boxes as JSON
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
### 2.
|
|
53
|
+
### 2. Embeddings in bulk
|
|
47
54
|
|
|
48
55
|
```python
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
for result in client.submit_many(
|
|
57
|
+
"coreml_embed",
|
|
58
|
+
[{"input": chunked(doc)} for doc in corpus],
|
|
52
59
|
max_concurrent=16,
|
|
53
|
-
)
|
|
60
|
+
):
|
|
61
|
+
save(result.output) # results stream as they complete
|
|
54
62
|
```
|
|
55
63
|
|
|
56
|
-
### 3.
|
|
64
|
+
### 3. Background removal
|
|
57
65
|
|
|
58
66
|
```python
|
|
59
|
-
job = client.
|
|
60
|
-
top = client.result(job).output
|
|
67
|
+
job = client.images.remove_background("product-shot.png")
|
|
61
68
|
```
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
Also live: speech synthesis, image classification/detection/pose, barcode
|
|
71
|
+
reading, HEIC conversion — plus the generic `client.submit(workload_id,
|
|
72
|
+
payload)` for anything marked **live** in
|
|
73
|
+
[the catalog](https://commoncompute.ai/workloads).
|
|
64
74
|
|
|
65
|
-
|
|
66
|
-
job = client.translate(catalog_descriptions, target_lang="de")
|
|
67
|
-
```
|
|
75
|
+
### In preview
|
|
68
76
|
|
|
69
|
-
|
|
77
|
+
`client.translate(...)` and `client.video.transcode(...)` run on preview
|
|
78
|
+
capacity — functional, not yet GA.
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
job = client.images.remove_background("product-shot.png")
|
|
73
|
-
```
|
|
80
|
+
### Not live yet
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
`client.
|
|
77
|
-
|
|
82
|
+
`client.transcription.*`, `client.rerank(...)`, `client.images.generate(...)`,
|
|
83
|
+
`client.chat.*`, and `client.build.ios_test(...)` target workloads still
|
|
84
|
+
marked *coming soon*: the API refuses them with a clear
|
|
85
|
+
`workload_not_available` error (HTTP 409) rather than queueing a job that
|
|
86
|
+
won't run. They activate automatically as those lanes go live — watch
|
|
78
87
|
[the catalog](https://commoncompute.ai/workloads).
|
|
79
88
|
|
|
80
89
|
## Price before execution, hard caps, dry runs
|
|
@@ -148,48 +157,59 @@ raw request/response dicts instead of typed `Job`/`TaskResult` objects.
|
|
|
148
157
|
|
|
149
158
|
## CLI
|
|
150
159
|
|
|
151
|
-
`pip install "commoncompute[cli]"` installs the `
|
|
160
|
+
`pip install "commoncompute[cli]"` installs the `commoncompute` command.
|
|
161
|
+
|
|
162
|
+
> **Why not a short `cc`?** Because `cc` is the Unix C compiler
|
|
163
|
+
> (`/usr/bin/cc`). Shipping a binary by that name puts it ahead of the real
|
|
164
|
+
> compiler on `PATH` for anyone whose Python bin directory sorts first, and
|
|
165
|
+
> every build that shells out to `cc` then fails with a CLI usage error
|
|
166
|
+
> instead of compiling. So `commoncompute` is the only command installed. If
|
|
167
|
+
> you want the shorthand, opt in yourself:
|
|
168
|
+
>
|
|
169
|
+
> ```bash
|
|
170
|
+
> alias cc="commoncompute" # add to ~/.zshrc or ~/.bashrc
|
|
171
|
+
> ```
|
|
152
172
|
|
|
153
173
|
```bash
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
commoncompute login # stores the key locally
|
|
175
|
+
commoncompute quote vision_ocr --units 5 # price + ETA, no execution
|
|
176
|
+
commoncompute submit coreml_embed --payload '{"input":["hi"]}' --wait
|
|
177
|
+
commoncompute jobs list
|
|
178
|
+
commoncompute jobs get <id>
|
|
179
|
+
commoncompute balance
|
|
180
|
+
commoncompute receipts export --format csv --out receipts.csv
|
|
161
181
|
```
|
|
162
182
|
|
|
163
183
|
### Commands
|
|
164
184
|
|
|
165
185
|
| Command | What it does |
|
|
166
186
|
|---------|--------------|
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `
|
|
170
|
-
| `
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
|
|
192
|
-
`
|
|
187
|
+
| `commoncompute login` / `commoncompute logout` | Store / remove the API key (browser approval, or `--api-key`) |
|
|
188
|
+
| `commoncompute whoami` | Show the account behind the current key |
|
|
189
|
+
| `commoncompute balance` | Current workspace balance |
|
|
190
|
+
| `commoncompute usage` | Spend + call-count rollups over a date range (`--start`, `--end`, `--group-by`) |
|
|
191
|
+
| `commoncompute spend` | Total spend over the last `--days` N, grouped by workload |
|
|
192
|
+
| `commoncompute tier` | Current volume tier and the next threshold |
|
|
193
|
+
| `commoncompute workloads` | List available workloads |
|
|
194
|
+
| `commoncompute models` | List models (`--workload` to filter) |
|
|
195
|
+
| `commoncompute quote` | Price + ETA for a workload without submitting (`--units`, `--priority`, `--model`) |
|
|
196
|
+
| `commoncompute submit` | Submit one job (`--payload/-f`, `--model`, `--priority`, `--wait`, `--timeout`) |
|
|
197
|
+
| `commoncompute submit-many` | Submit a JSONL file of payloads; stream one result per line as NDJSON (`--input/-i`, `--max-concurrent`, `--no-wait`) |
|
|
198
|
+
| `commoncompute chat` | One-shot chat message to a model (`--model`, `--stream/--no-stream`) |
|
|
199
|
+
| `commoncompute embed` | Embed a single string (prints the vector length) |
|
|
200
|
+
| `commoncompute playground` | Open the web playground |
|
|
201
|
+
| `commoncompute jobs list` | Recent submissions, newest first (`--limit/-n`) |
|
|
202
|
+
| `commoncompute jobs get <id>` | Fetch one job |
|
|
203
|
+
| `commoncompute jobs wait <id>` | Poll a job to a terminal state (`--timeout/-t`) |
|
|
204
|
+
| `commoncompute jobs events <id>` | Event timeline for a job |
|
|
205
|
+
| `commoncompute jobs download <id>` | Download a job's result (`--out/-o`, else stdout) |
|
|
206
|
+
| `commoncompute keys list` / `create` / `revoke` | Manage API keys |
|
|
207
|
+
| `commoncompute receipts list` | Receipts for completed jobs (`--limit/-n`) |
|
|
208
|
+
| `commoncompute receipts get <id>` | Signed receipt for a single job |
|
|
209
|
+
| `commoncompute receipts export` | Export receipts as CSV or JSON (`--format/-f`, `--out/-o`, `--limit/-n`) |
|
|
210
|
+
| `commoncompute config path` / `show` / `set` / `unset` | Inspect and edit local settings (see below) |
|
|
211
|
+
|
|
212
|
+
`commoncompute --version` (or `-V`) prints the version. Every read command that renders a
|
|
193
213
|
table also accepts **`--json`** for plain, ANSI-free machine-readable output —
|
|
194
214
|
`whoami`, `balance`, `usage`, `spend`, `tier`, `workloads`, `models`, `quote`,
|
|
195
215
|
`submit`, `jobs list/get/wait/events`, `keys list`, and `receipts list`.
|
|
@@ -199,20 +219,20 @@ table also accepts **`--json`** for plain, ANSI-free machine-readable output —
|
|
|
199
219
|
Typer ships completion for bash, zsh, fish, and PowerShell:
|
|
200
220
|
|
|
201
221
|
```bash
|
|
202
|
-
|
|
203
|
-
|
|
222
|
+
commoncompute --install-completion # install for the current shell
|
|
223
|
+
commoncompute --show-completion # print the script to inspect or customise
|
|
204
224
|
```
|
|
205
225
|
|
|
206
226
|
### Exit codes
|
|
207
227
|
|
|
208
|
-
Scripts can branch on `
|
|
228
|
+
Scripts can branch on `commoncompute`'s exit status:
|
|
209
229
|
|
|
210
230
|
| Code | Meaning |
|
|
211
231
|
|------|---------|
|
|
212
232
|
| `0` | Success |
|
|
213
233
|
| `1` | API or runtime error (network, server, bad request) |
|
|
214
234
|
| `2` | Usage error — missing/invalid arguments, or no credentials found |
|
|
215
|
-
| `3` | The job reached a **failed** terminal state (`failed` / `dead_letter` / `cancelled`) — `
|
|
235
|
+
| `3` | The job reached a **failed** terminal state (`failed` / `dead_letter` / `cancelled`) — `commoncompute jobs wait` and `commoncompute submit --wait` only |
|
|
216
236
|
|
|
217
237
|
## Migrating from OpenAI (optional)
|
|
218
238
|
|
|
@@ -281,14 +301,14 @@ Environment variables take precedence over both files at runtime:
|
|
|
281
301
|
Inspect and edit the local config from the CLI:
|
|
282
302
|
|
|
283
303
|
```bash
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
304
|
+
commoncompute config path # print the config directory
|
|
305
|
+
commoncompute config show # settings + active credential source (key masked)
|
|
306
|
+
commoncompute config set base_url https://api.commoncompute.ai
|
|
307
|
+
commoncompute config set org my-workspace
|
|
308
|
+
commoncompute config unset org
|
|
289
309
|
```
|
|
290
310
|
|
|
291
|
-
Env vars still win at runtime — `
|
|
311
|
+
Env vars still win at runtime — `commoncompute config set` writes the file, but
|
|
292
312
|
`CC_BASE_URL` / `CC_ORG` override it for a given process.
|
|
293
313
|
|
|
294
314
|
Python 3.9+. Core dependencies: `httpx`, `pydantic`. MIT license.
|
|
@@ -11,33 +11,26 @@ Quickstart::
|
|
|
11
11
|
client = cc.Client(api_key="cc_live_...")
|
|
12
12
|
print(client.balance())
|
|
13
13
|
|
|
14
|
-
#
|
|
15
|
-
reply = client.chat.create(
|
|
16
|
-
model="qwen-2.5-7b",
|
|
17
|
-
messages=[{"role": "user", "content": "hi"}],
|
|
18
|
-
)
|
|
19
|
-
print(reply["choices"][0]["message"]["content"])
|
|
20
|
-
|
|
21
|
-
# Native job submission
|
|
14
|
+
# Native job submission (embeddings — live today)
|
|
22
15
|
job = client.jobs.submit(
|
|
23
16
|
workload_id="coreml_embed",
|
|
24
17
|
payload={"input": ["hello world"]},
|
|
25
18
|
)
|
|
26
19
|
result = client.jobs.wait(job["id"])
|
|
27
20
|
|
|
28
|
-
|
|
21
|
+
# OpenAI-compatible embeddings
|
|
22
|
+
vectors = client.embeddings.create(input=["hello world"], model="bge-base")
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
print(delta, end="", flush=True)
|
|
24
|
+
`client.chat.*` targets LLM workloads that are still marked *coming soon*
|
|
25
|
+
in the catalog — the API declines them with `workload_not_available`
|
|
26
|
+
(HTTP 409) until they go live. See https://commoncompute.ai/workloads.
|
|
34
27
|
"""
|
|
35
28
|
|
|
36
29
|
# MUST come before any submodule imports — _transport.py reads
|
|
37
30
|
# `commoncompute.__version__` at import time for the User-Agent header,
|
|
38
31
|
# and the previous ordering (`__version__` defined at the bottom) made
|
|
39
32
|
# every clean install of the SDK fail with a circular ImportError.
|
|
40
|
-
__version__ = "0.
|
|
33
|
+
__version__ = "0.3.1"
|
|
41
34
|
|
|
42
35
|
from .client import Client, AsyncClient
|
|
43
36
|
from .errors import (
|
|
@@ -278,8 +278,10 @@ class _KeysAsync:
|
|
|
278
278
|
async def list(self) -> list[dict[str, Any]]:
|
|
279
279
|
return (await self._t.request("GET", "/v1/me/keys")).get("keys", [])
|
|
280
280
|
|
|
281
|
-
async def create(self, *, name: str, mode: str = "live", scopes: "Optional[Sequence[str]]" = None) -> dict[str, Any]:
|
|
281
|
+
async def create(self, *, name: str, mode: str = "live", scopes: "Optional[Sequence[str]]" = None, password: "Optional[str]" = None) -> dict[str, Any]:
|
|
282
282
|
body: dict[str, Any] = {"name": name, "mode": mode}
|
|
283
|
+
if password:
|
|
284
|
+
body["password"] = password
|
|
283
285
|
if scopes:
|
|
284
286
|
body["scopes"] = scopes
|
|
285
287
|
return await self._t.request("POST", "/v1/me/keys", json_body=body)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Shared credential + config resolution for the SDK, CLI, and connect().
|
|
2
2
|
|
|
3
|
-
One module owns where keys and settings live, so ``Client()``,
|
|
3
|
+
One module owns where keys and settings live, so ``Client()``,
|
|
4
|
+
``commoncompute login``,
|
|
4
5
|
and ``commoncompute.connect()`` can never disagree again.
|
|
5
6
|
|
|
6
7
|
Canonical location (respects ``$CC_CONFIG_DIR``)::
|
|
@@ -30,7 +31,7 @@ import os
|
|
|
30
31
|
from pathlib import Path
|
|
31
32
|
from typing import Dict, Mapping, Optional, Tuple
|
|
32
33
|
|
|
33
|
-
#: Settings keys `
|
|
34
|
+
#: Settings keys `commoncompute config set` accepts (everything else is rejected).
|
|
34
35
|
SETTINGS_KEYS = ("base_url", "org")
|
|
35
36
|
|
|
36
37
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
# @generated
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
1
|
+
# @generated from Common Compute's internal workload catalog — DO NOT EDIT.
|
|
2
|
+
#
|
|
3
|
+
# This file is emitted by an internal codegen step and is not regenerable from
|
|
4
|
+
# this repository. Edits here will be overwritten; the catalog is the source of
|
|
5
|
+
# truth and drift is caught before release.
|
|
6
|
+
#
|
|
7
|
+
# Contains workload IDs and image-name routing heuristics only.
|
|
5
8
|
from __future__ import annotations
|
|
6
9
|
|
|
7
10
|
# Every workload id in the catalog. Used to decide whether a jobDefinition head
|
|
@@ -143,13 +143,13 @@ class _BaseTransport:
|
|
|
143
143
|
if not resolved_key:
|
|
144
144
|
raise CommonComputeError(
|
|
145
145
|
"No API key. Run commoncompute.connect() (opens the browser, "
|
|
146
|
-
"no copy-paste) or `
|
|
146
|
+
"no copy-paste) or `commoncompute login` from a terminal — or pass "
|
|
147
147
|
"api_key=... / set CC_API_KEY.",
|
|
148
148
|
status_code=None,
|
|
149
149
|
code="missing_api_key",
|
|
150
150
|
)
|
|
151
151
|
self._api_key = resolved_key
|
|
152
|
-
# base_url / org: explicit arg → env → `
|
|
152
|
+
# base_url / org: explicit arg → env → `commoncompute config set` settings → default.
|
|
153
153
|
settings = _config.load_settings()
|
|
154
154
|
self._base_url = (
|
|
155
155
|
base_url
|
|
@@ -103,11 +103,10 @@ def _to_iso(ms: Optional[int]) -> Optional[str]:
|
|
|
103
103
|
# Heuristic: anything containing one of these workload ids gets routed
|
|
104
104
|
# directly. Otherwise we default to ``coreml_embed`` (the most common
|
|
105
105
|
# batch workload migrated from AWS Batch + bge-* embeddings pipelines).
|
|
106
|
-
# Workload identity comes from the generated catalog mirror
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
110
|
-
# npx tsx packages/workloads/codegen/emit-sdk-workloads.ts
|
|
106
|
+
# Workload identity comes from the generated catalog mirror
|
|
107
|
+
# (``_generated_workloads.py``) so this shim resolves jobDefinitions
|
|
108
|
+
# identically to the server side and to the Node SDK, instead of drifting
|
|
109
|
+
# from a hand-maintained list.
|
|
111
110
|
from ._generated_workloads import IMAGE_PATTERNS as _IMAGE_PATTERN_SOURCES
|
|
112
111
|
from ._generated_workloads import KNOWN_WORKLOAD_IDS as _KNOWN_WORKLOADS
|
|
113
112
|
|
|
@@ -403,7 +402,7 @@ class BatchClient:
|
|
|
403
402
|
"""Mirror AWS describe_jobs — returns ``{"jobs": [...]}``.
|
|
404
403
|
|
|
405
404
|
Just-submitted jobs may not be queryable for ~100ms while the
|
|
406
|
-
underlying
|
|
405
|
+
underlying row propagates across the backing datastore's read replicas.
|
|
407
406
|
We absorb a single 404 by retrying once after 250ms, which is
|
|
408
407
|
enough to mask the eventual-consistency window in practice."""
|
|
409
408
|
out: list[dict[str, Any]] = []
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
"""`
|
|
1
|
+
"""`commoncompute` command-line interface.
|
|
2
|
+
|
|
3
|
+
Installed as ``commoncompute`` via the pyproject entry point. A short ``cc``
|
|
4
|
+
alias is deliberately not installed — it would shadow the Unix C compiler
|
|
5
|
+
(``/usr/bin/cc``) and break builds that invoke it. Add
|
|
6
|
+
``alias cc="commoncompute"`` to your shell rc if you want the shorthand.
|
|
2
7
|
|
|
3
|
-
Installed as ``cc`` and ``commoncompute`` via the pyproject entry point.
|
|
4
8
|
Uses Typer for argparsing + Rich for pretty output. Reads credentials
|
|
5
9
|
from (in order): ``--api-key`` flag, ``CC_API_KEY`` env var, the canonical
|
|
6
10
|
credentials file at ``~/.config/commoncompute/credentials``, then the
|
|
@@ -11,7 +15,8 @@ Exit codes:
|
|
|
11
15
|
1 API / runtime error
|
|
12
16
|
2 usage error / missing credentials
|
|
13
17
|
3 a job reached a *failed* terminal state (failed / dead_letter /
|
|
14
|
-
cancelled) while waiting — ``
|
|
18
|
+
cancelled) while waiting — ``commoncompute jobs wait`` and
|
|
19
|
+
``commoncompute submit --wait``
|
|
15
20
|
"""
|
|
16
21
|
|
|
17
22
|
from __future__ import annotations
|
|
@@ -31,7 +36,7 @@ try:
|
|
|
31
36
|
from rich.panel import Panel
|
|
32
37
|
except ImportError: # CLI deps are the [cli] extra, not core deps
|
|
33
38
|
print(
|
|
34
|
-
"The `
|
|
39
|
+
"The `commoncompute` CLI needs the cli extra: pip install \"commoncompute[cli]\"",
|
|
35
40
|
file=sys.stderr,
|
|
36
41
|
)
|
|
37
42
|
raise SystemExit(2)
|
|
@@ -41,7 +46,7 @@ from .client import Client
|
|
|
41
46
|
from .errors import CommonComputeError
|
|
42
47
|
|
|
43
48
|
app = typer.Typer(
|
|
44
|
-
name="
|
|
49
|
+
name="commoncompute",
|
|
45
50
|
add_completion=True,
|
|
46
51
|
no_args_is_help=True,
|
|
47
52
|
help="Common Compute CLI — submit jobs, check spend, manage keys.",
|
|
@@ -63,7 +68,7 @@ err_console = Console(stderr=True, style="red")
|
|
|
63
68
|
def _version_callback(value: bool) -> None:
|
|
64
69
|
if value:
|
|
65
70
|
from . import __version__
|
|
66
|
-
print(f"
|
|
71
|
+
print(f"commoncompute {__version__}")
|
|
67
72
|
raise typer.Exit()
|
|
68
73
|
|
|
69
74
|
|
|
@@ -92,7 +97,9 @@ def _load_api_key(override: Optional[str] = None) -> Optional[str]:
|
|
|
92
97
|
def _client(api_key: Optional[str] = None) -> Client:
|
|
93
98
|
key = _load_api_key(api_key)
|
|
94
99
|
if not key:
|
|
95
|
-
err_console.print(
|
|
100
|
+
err_console.print(
|
|
101
|
+
"No API key found. Run [bold]commoncompute login[/bold] or set [bold]CC_API_KEY[/bold]."
|
|
102
|
+
)
|
|
96
103
|
raise typer.Exit(2)
|
|
97
104
|
try:
|
|
98
105
|
return Client(api_key=key)
|
|
@@ -159,7 +166,7 @@ def logout() -> None:
|
|
|
159
166
|
console.print("Nothing to remove.")
|
|
160
167
|
|
|
161
168
|
|
|
162
|
-
# ───
|
|
169
|
+
# ─── commoncompute config ───────────────────────────────────────────────
|
|
163
170
|
# Plain print() (not rich) on purpose: the output is meant for shells and
|
|
164
171
|
# scripts, and rich's 80-col soft-wrap would mangle long paths.
|
|
165
172
|
|
|
@@ -182,7 +189,7 @@ def config_show() -> None:
|
|
|
182
189
|
if key:
|
|
183
190
|
print(f"api key: {key[:8]}… (from {source})")
|
|
184
191
|
else:
|
|
185
|
-
print("api key: (none found — run `
|
|
192
|
+
print("api key: (none found — run `commoncompute login`)")
|
|
186
193
|
|
|
187
194
|
|
|
188
195
|
@config_app.command("set")
|
|
@@ -407,8 +414,10 @@ def estimate(
|
|
|
407
414
|
model: Optional[str] = typer.Option(None, "--model", "-m"),
|
|
408
415
|
as_json: bool = typer.Option(False, "--json", help="Raw JSON output."),
|
|
409
416
|
) -> None:
|
|
410
|
-
"""Deprecated alias for `
|
|
411
|
-
err_console.print(
|
|
417
|
+
"""Deprecated alias for `commoncompute quote` (kept for back-compat)."""
|
|
418
|
+
err_console.print(
|
|
419
|
+
"`commoncompute estimate` is deprecated; use `commoncompute quote` instead."
|
|
420
|
+
)
|
|
412
421
|
quote(workload=workload, units=units, priority=priority, model=model, as_json=as_json)
|
|
413
422
|
|
|
414
423
|
|
|
@@ -426,10 +435,46 @@ def _wait_job(client: Client, job_id: str, timeout: float, *, quiet: bool):
|
|
|
426
435
|
return client.wait(job_id, timeout=timeout, on_progress=_tick)
|
|
427
436
|
|
|
428
437
|
|
|
438
|
+
def _parse_payload_arg(payload: str) -> object:
|
|
439
|
+
"""Resolve --payload: @- (stdin), @path or bare path (file), or inline JSON.
|
|
440
|
+
|
|
441
|
+
The help has always said "path to JSON payload file", but the code only
|
|
442
|
+
honoured that with an @ prefix — a bare path fell through to json.loads()
|
|
443
|
+
and died with a raw JSONDecodeError traceback. Accept the documented
|
|
444
|
+
form, keep both @ forms, and turn every failure into a clean CLI error.
|
|
445
|
+
"""
|
|
446
|
+
try:
|
|
447
|
+
if payload == "@-":
|
|
448
|
+
return json.load(sys.stdin)
|
|
449
|
+
if payload.startswith("@"):
|
|
450
|
+
return json.loads(Path(payload[1:]).read_text())
|
|
451
|
+
p = Path(payload)
|
|
452
|
+
if p.exists():
|
|
453
|
+
return json.loads(p.read_text())
|
|
454
|
+
# Not a file on disk — treat as inline JSON. A path-like string that
|
|
455
|
+
# simply doesn't exist gets a hint instead of a JSON parse error.
|
|
456
|
+
try:
|
|
457
|
+
return json.loads(payload)
|
|
458
|
+
except json.JSONDecodeError:
|
|
459
|
+
if payload.endswith(".json") or "/" in payload:
|
|
460
|
+
err_console.print(f"[red]Error:[/red] payload file not found: {payload}")
|
|
461
|
+
else:
|
|
462
|
+
err_console.print(f"[red]Error:[/red] --payload is not a file, not valid inline JSON: {payload!r}")
|
|
463
|
+
raise typer.Exit(2)
|
|
464
|
+
except typer.Exit:
|
|
465
|
+
raise
|
|
466
|
+
except json.JSONDecodeError as e:
|
|
467
|
+
err_console.print(f"[red]Error:[/red] invalid JSON in payload ({e.msg} at line {e.lineno}, column {e.colno})")
|
|
468
|
+
raise typer.Exit(2)
|
|
469
|
+
except OSError as e:
|
|
470
|
+
err_console.print(f"[red]Error:[/red] cannot read payload: {e}")
|
|
471
|
+
raise typer.Exit(2)
|
|
472
|
+
|
|
473
|
+
|
|
429
474
|
@app.command()
|
|
430
475
|
def submit(
|
|
431
476
|
workload: str = typer.Argument(..., help="Workload id."),
|
|
432
|
-
payload: Optional[str] = typer.Option(None, "--payload", "-f", help="Path to JSON payload file,
|
|
477
|
+
payload: Optional[str] = typer.Option(None, "--payload", "-f", help="Path to a JSON payload file, @- for stdin, or an inline JSON string."),
|
|
433
478
|
model: Optional[str] = typer.Option(None, "--model", "-m"),
|
|
434
479
|
priority: str = typer.Option("standard", "--priority", "-p"),
|
|
435
480
|
wait: bool = typer.Option(False, "--wait", help="Block until the job finishes."),
|
|
@@ -439,12 +484,7 @@ def submit(
|
|
|
439
484
|
"""Submit a native Common Compute job."""
|
|
440
485
|
body: object = None
|
|
441
486
|
if payload:
|
|
442
|
-
|
|
443
|
-
body = json.load(sys.stdin)
|
|
444
|
-
elif payload.startswith("@"):
|
|
445
|
-
body = json.loads(Path(payload[1:]).read_text())
|
|
446
|
-
else:
|
|
447
|
-
body = json.loads(payload)
|
|
487
|
+
body = _parse_payload_arg(payload)
|
|
448
488
|
c = _client()
|
|
449
489
|
try:
|
|
450
490
|
job = c.jobs.submit(workload, payload=body, model_id=model, priority=priority)
|
|
@@ -575,7 +615,7 @@ def jobs_status(
|
|
|
575
615
|
task_id: str,
|
|
576
616
|
as_json: bool = typer.Option(False, "--json", help="Raw JSON output (no ANSI)."),
|
|
577
617
|
) -> None:
|
|
578
|
-
"""Alias for `
|
|
618
|
+
"""Alias for `commoncompute jobs get`."""
|
|
579
619
|
jobs_get(task_id=task_id, as_json=as_json)
|
|
580
620
|
|
|
581
621
|
|
|
@@ -263,10 +263,28 @@ class _KeysSync:
|
|
|
263
263
|
def list(self) -> list[dict[str, Any]]:
|
|
264
264
|
return self._t.request("GET", "/v1/me/keys").get("keys", [])
|
|
265
265
|
|
|
266
|
-
def create(
|
|
266
|
+
def create(
|
|
267
|
+
self,
|
|
268
|
+
*,
|
|
269
|
+
name: str,
|
|
270
|
+
mode: str = "live",
|
|
271
|
+
scopes: "Optional[Sequence[str]]" = None,
|
|
272
|
+
password: "Optional[str]" = None,
|
|
273
|
+
) -> dict[str, Any]:
|
|
274
|
+
"""Create an API key.
|
|
275
|
+
|
|
276
|
+
Requires a signed-in *session* plus the account password. An API key
|
|
277
|
+
cannot create another API key (the server returns 403
|
|
278
|
+
``api_key_cannot_mint``) — otherwise revoking a leaked key would not
|
|
279
|
+
revoke the keys it had spawned. Since this SDK normally authenticates
|
|
280
|
+
with an API key, most callers should create keys in the dashboard at
|
|
281
|
+
/app/api-keys instead.
|
|
282
|
+
"""
|
|
267
283
|
body: dict[str, Any] = {"name": name, "mode": mode}
|
|
268
284
|
if scopes:
|
|
269
285
|
body["scopes"] = scopes
|
|
286
|
+
if password:
|
|
287
|
+
body["password"] = password
|
|
270
288
|
return self._t.request("POST", "/v1/me/keys", json_body=body)
|
|
271
289
|
|
|
272
290
|
def revoke(self, key_id: str) -> None:
|
|
@@ -27,12 +27,31 @@ from .models import Job, Quote, Receipt, TaskResult
|
|
|
27
27
|
|
|
28
28
|
FileInput = Union[str, Path, bytes, io.BufferedReader]
|
|
29
29
|
|
|
30
|
+
# Schemes recognised as "this is a URI, not a local path". Only https:// can
|
|
31
|
+
# actually be fetched: the provider's download gate hard-rejects every other
|
|
32
|
+
# scheme (TrustedDownload.swift — "only https"), and http:// specifically is
|
|
33
|
+
# refused because a job input must not travel in the clear.
|
|
34
|
+
#
|
|
35
|
+
# The others stay in this tuple ON PURPOSE. Dropping them would make an s3://
|
|
36
|
+
# URI fall through to the local-path branch and raise a confusing
|
|
37
|
+
# "No such file: s3://bucket/key"; keeping them lets _file_payload reject the
|
|
38
|
+
# scheme by name, at submit time, instead of the job dispatching and failing
|
|
39
|
+
# on someone's Mac minutes later (2026-08-01 audit — the SDKs documented all
|
|
40
|
+
# five schemes and only one ever worked).
|
|
30
41
|
_URI_SCHEMES = ("http://", "https://", "s3://", "r2://", "gs://")
|
|
42
|
+
_FETCHABLE_URI_SCHEMES = ("https://",)
|
|
31
43
|
|
|
32
44
|
|
|
33
45
|
def _file_payload(f: FileInput, *, allowed_suffixes: Optional[Sequence[str]] = None) -> dict:
|
|
34
46
|
"""Normalise a file input into the job-payload contract."""
|
|
35
47
|
if isinstance(f, str) and f.startswith(_URI_SCHEMES):
|
|
48
|
+
if not f.startswith(_FETCHABLE_URI_SCHEMES):
|
|
49
|
+
scheme = f.split("://", 1)[0]
|
|
50
|
+
raise UnsupportedFormatError(
|
|
51
|
+
f"{scheme}:// inputs are not supported — providers can only fetch https:// URLs. "
|
|
52
|
+
f"Pass a local path (the file is uploaded for you) or a presigned https:// URL.",
|
|
53
|
+
code="unsupported_input_scheme",
|
|
54
|
+
)
|
|
36
55
|
return {"input_uri": f}
|
|
37
56
|
if isinstance(f, (str, Path)):
|
|
38
57
|
p = Path(f)
|
|
@@ -367,6 +386,14 @@ class Video(_TaskBase):
|
|
|
367
386
|
max_spend_usd: Optional[float] = None,
|
|
368
387
|
dry_run: bool = False,
|
|
369
388
|
) -> Union[Job, Quote]:
|
|
389
|
+
"""Transcode a video with VideoToolbox hardware encoders.
|
|
390
|
+
|
|
391
|
+
``output_format`` selects the codec (``"h264"`` / ``"hevc"`` /
|
|
392
|
+
``"prores"``); ``codec=`` overrides it if both are given.
|
|
393
|
+
``resolution`` is not yet implemented server-side — a job that sets
|
|
394
|
+
it fails fast with a clear error instead of silently encoding at
|
|
395
|
+
the source's native size.
|
|
396
|
+
"""
|
|
370
397
|
workload_id, payload, units, model_id = _transcode_request(
|
|
371
398
|
input, output_format, resolution=resolution, codec=codec, output_minutes=output_minutes,
|
|
372
399
|
)
|
|
@@ -38,11 +38,15 @@ dependencies = [
|
|
|
38
38
|
[project.urls]
|
|
39
39
|
Homepage = "https://commoncompute.ai"
|
|
40
40
|
Documentation = "https://commoncompute.ai/docs"
|
|
41
|
-
Source = "https://github.com/
|
|
41
|
+
Source = "https://github.com/commoncompute/sdk"
|
|
42
42
|
Changelog = "https://commoncompute.ai/changelog"
|
|
43
43
|
|
|
44
44
|
[project.scripts]
|
|
45
|
-
cc
|
|
45
|
+
# `commoncompute` is the only installed command. A short `cc` alias is
|
|
46
|
+
# deliberately NOT shipped: it shadows the Unix C compiler (/usr/bin/cc), so
|
|
47
|
+
# installing it into a PATH-early location silently breaks any build that
|
|
48
|
+
# invokes `cc`. Users who want the shorthand opt in themselves with
|
|
49
|
+
# `alias cc="commoncompute"`.
|
|
46
50
|
commoncompute = "commoncompute.cli:app"
|
|
47
51
|
|
|
48
52
|
[project.optional-dependencies]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|