sference-cli 0.1.4__tar.gz → 0.1.6__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.
- {sference_cli-0.1.4 → sference_cli-0.1.6}/PKG-INFO +4 -4
- {sference_cli-0.1.4 → sference_cli-0.1.6}/README.md +2 -2
- {sference_cli-0.1.4 → sference_cli-0.1.6}/pyproject.toml +2 -2
- {sference_cli-0.1.4 → sference_cli-0.1.6}/sference_cli/main.py +48 -7
- {sference_cli-0.1.4 → sference_cli-0.1.6}/.gitignore +0 -0
- {sference_cli-0.1.4 → sference_cli-0.1.6}/LICENSE +0 -0
- {sference_cli-0.1.4 → sference_cli-0.1.6}/sference_cli/__init__.py +0 -0
- {sference_cli-0.1.4 → sference_cli-0.1.6}/sference_cli/launch.py +0 -0
- {sference_cli-0.1.4 → sference_cli-0.1.6}/sference_cli/stream_cache.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sference-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
4
4
|
Summary: sference command-line interface
|
|
5
5
|
Project-URL: Homepage, https://sference.com
|
|
6
6
|
Project-URL: Repository, https://github.com/s-ference/sference
|
|
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Topic :: Utilities
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: sference-sdk>=0.1.
|
|
24
|
+
Requires-Dist: sference-sdk>=0.1.6
|
|
25
25
|
Requires-Dist: typer>=0.24.1
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
|
|
@@ -148,7 +148,7 @@ Requires the [Pi CLI](https://pi.dev/docs) on `PATH`. Writes a `sference` provid
|
|
|
148
148
|
| Command | Description |
|
|
149
149
|
|---------|-------------|
|
|
150
150
|
| `sference batch list` | List batches (table; `--json` for raw payload) |
|
|
151
|
-
| `sference batch submit` | Submit a JSONL file (`--input-file`, optional `--model` for content-only lines, `--window` `
|
|
151
|
+
| `sference batch submit` | Submit a JSONL file (`--input-file`, optional `--model` for content-only lines, `--window` `24h`) |
|
|
152
152
|
| `sference batch stream` | Submit, wait, print **JSONL results on stdout** (see below) |
|
|
153
153
|
| `sference batch status` | Get one batch (`--batch-id`, `--json`) |
|
|
154
154
|
| `sference batch wait` | Poll until terminal state (`--batch-id`, `--poll-interval`, `--timeout`, `--json`) |
|
|
@@ -170,7 +170,7 @@ Long-lived **streams** are separate from **batches**: you create a stream, submi
|
|
|
170
170
|
|
|
171
171
|
| Command | Description |
|
|
172
172
|
|---------|-------------|
|
|
173
|
-
| `sference stream create` | Create a stream (`--name`, `--window` `
|
|
173
|
+
| `sference stream create` | Create a stream (`--name`, `--window` `24h`, `--json`) |
|
|
174
174
|
| `sference stream list` | List streams (`--json`) |
|
|
175
175
|
| `sference stream status` | Full detail + counters (`--stream-id`, `--json`) |
|
|
176
176
|
| `sference stream submit` | Create responses from JSONL via `POST /v1/responses` per line (`metadata.stream_id` set automatically; `--stream-id`, `--input-file`, `--model` required for content-only lines) — per line: OpenAI batch-style `{custom_id?, method, url, body}` or content-only `{content}` |
|
|
@@ -121,7 +121,7 @@ Requires the [Pi CLI](https://pi.dev/docs) on `PATH`. Writes a `sference` provid
|
|
|
121
121
|
| Command | Description |
|
|
122
122
|
|---------|-------------|
|
|
123
123
|
| `sference batch list` | List batches (table; `--json` for raw payload) |
|
|
124
|
-
| `sference batch submit` | Submit a JSONL file (`--input-file`, optional `--model` for content-only lines, `--window` `
|
|
124
|
+
| `sference batch submit` | Submit a JSONL file (`--input-file`, optional `--model` for content-only lines, `--window` `24h`) |
|
|
125
125
|
| `sference batch stream` | Submit, wait, print **JSONL results on stdout** (see below) |
|
|
126
126
|
| `sference batch status` | Get one batch (`--batch-id`, `--json`) |
|
|
127
127
|
| `sference batch wait` | Poll until terminal state (`--batch-id`, `--poll-interval`, `--timeout`, `--json`) |
|
|
@@ -143,7 +143,7 @@ Long-lived **streams** are separate from **batches**: you create a stream, submi
|
|
|
143
143
|
|
|
144
144
|
| Command | Description |
|
|
145
145
|
|---------|-------------|
|
|
146
|
-
| `sference stream create` | Create a stream (`--name`, `--window` `
|
|
146
|
+
| `sference stream create` | Create a stream (`--name`, `--window` `24h`, `--json`) |
|
|
147
147
|
| `sference stream list` | List streams (`--json`) |
|
|
148
148
|
| `sference stream status` | Full detail + counters (`--stream-id`, `--json`) |
|
|
149
149
|
| `sference stream submit` | Create responses from JSONL via `POST /v1/responses` per line (`metadata.stream_id` set automatically; `--stream-id`, `--input-file`, `--model` required for content-only lines) — per line: OpenAI batch-style `{custom_id?, method, url, body}` or content-only `{content}` |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sference-cli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.6"
|
|
4
4
|
description = "sference command-line interface"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
]
|
|
24
24
|
dependencies = [
|
|
25
25
|
"typer>=0.24.1",
|
|
26
|
-
"sference-sdk>=0.1.
|
|
26
|
+
"sference-sdk>=0.1.6",
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
[project.urls]
|
|
@@ -32,11 +32,13 @@ batch_app = typer.Typer(help="Batch commands", invoke_without_command=True)
|
|
|
32
32
|
stream_app = typer.Typer(help="Stream commands", invoke_without_command=True)
|
|
33
33
|
responses_app = typer.Typer(help="Responses commands", invoke_without_command=True)
|
|
34
34
|
models_app = typer.Typer(help="List models (GET /v1/models)", invoke_without_command=True)
|
|
35
|
+
embeddings_app = typer.Typer(help="Embeddings commands", invoke_without_command=True)
|
|
35
36
|
app.add_typer(auth_app, name="auth")
|
|
36
37
|
app.add_typer(batch_app, name="batch")
|
|
37
38
|
app.add_typer(stream_app, name="stream")
|
|
38
39
|
app.add_typer(responses_app, name="responses")
|
|
39
40
|
app.add_typer(models_app, name="models")
|
|
41
|
+
app.add_typer(embeddings_app, name="embeddings")
|
|
40
42
|
register_launch_commands(app)
|
|
41
43
|
|
|
42
44
|
CREDENTIALS_PATH = Path.home() / ".sference" / "credentials.json"
|
|
@@ -163,6 +165,14 @@ def _capability_flag(caps: object, key: str) -> str:
|
|
|
163
165
|
return "—"
|
|
164
166
|
|
|
165
167
|
|
|
168
|
+
def _modality_label(raw: object) -> str:
|
|
169
|
+
if not isinstance(raw, str) or not raw:
|
|
170
|
+
return "—"
|
|
171
|
+
if raw.startswith("text_"):
|
|
172
|
+
return raw.removeprefix("text_")
|
|
173
|
+
return raw
|
|
174
|
+
|
|
175
|
+
|
|
166
176
|
def _print_models_table(payload: object) -> None:
|
|
167
177
|
if not isinstance(payload, dict):
|
|
168
178
|
typer.echo(str(payload))
|
|
@@ -175,9 +185,9 @@ def _print_models_table(payload: object) -> None:
|
|
|
175
185
|
typer.echo("No models.")
|
|
176
186
|
return
|
|
177
187
|
|
|
178
|
-
w_id, w_name, w_ctx, w_vis, w_pdf, w_think, w_tools = 34, 18, 8, 6, 4, 8, 5
|
|
188
|
+
w_id, w_name, w_mod, w_ctx, w_vis, w_pdf, w_think, w_tools = 34, 18, 10, 8, 6, 4, 8, 5
|
|
179
189
|
typer.echo(
|
|
180
|
-
f"{'id':<{w_id}} {'display_name':<{w_name}} {'context':>{w_ctx}} "
|
|
190
|
+
f"{'id':<{w_id}} {'display_name':<{w_name}} {'modality':<{w_mod}} {'context':>{w_ctx}} "
|
|
181
191
|
f"{'vision':>{w_vis}} {'pdf':>{w_pdf}} {'thinking':>{w_think}} {'tools':>{w_tools}}"
|
|
182
192
|
)
|
|
183
193
|
for row in rows:
|
|
@@ -189,6 +199,9 @@ def _print_models_table(payload: object) -> None:
|
|
|
189
199
|
display_name = str(row.get("display_name") or "")
|
|
190
200
|
if len(display_name) > w_name:
|
|
191
201
|
display_name = display_name[: w_name - 1] + "…"
|
|
202
|
+
modality = _modality_label(row.get("modality"))
|
|
203
|
+
if len(modality) > w_mod:
|
|
204
|
+
modality = modality[: w_mod - 1] + "…"
|
|
192
205
|
ctx_raw = row.get("context_tokens")
|
|
193
206
|
context = str(ctx_raw) if isinstance(ctx_raw, int) else "—"
|
|
194
207
|
caps = row.get("capabilities")
|
|
@@ -197,7 +210,7 @@ def _print_models_table(payload: object) -> None:
|
|
|
197
210
|
thinking = _capability_flag(caps, "thinking")
|
|
198
211
|
tools = _capability_flag(caps, "tools")
|
|
199
212
|
typer.echo(
|
|
200
|
-
f"{model_id:<{w_id}} {display_name:<{w_name}} {context:>{w_ctx}} "
|
|
213
|
+
f"{model_id:<{w_id}} {display_name:<{w_name}} {modality:<{w_mod}} {context:>{w_ctx}} "
|
|
201
214
|
f"{vision:>{w_vis}} {pdf:>{w_pdf}} {thinking:>{w_think}} {tools:>{w_tools}}"
|
|
202
215
|
)
|
|
203
216
|
|
|
@@ -286,6 +299,34 @@ def models_list(
|
|
|
286
299
|
_list_models(client=client, as_json=as_json)
|
|
287
300
|
|
|
288
301
|
|
|
302
|
+
@embeddings_app.command("create")
|
|
303
|
+
def embeddings_create(
|
|
304
|
+
model: str = typer.Option(..., "--model"),
|
|
305
|
+
input_text: list[str] = typer.Option(..., "--input", help="Text to embed (repeat for multiple strings)."),
|
|
306
|
+
encoding_format: str = typer.Option("float", "--encoding-format", help='"float" or "base64".'),
|
|
307
|
+
dimensions: int | None = typer.Option(None, "--dimensions"),
|
|
308
|
+
timeout: float = typer.Option(600.0, "--timeout", help="HTTP read timeout in seconds."),
|
|
309
|
+
base_url: str = typer.Option("https://api.sference.com"),
|
|
310
|
+
as_json: bool = typer.Option(False, "--json"),
|
|
311
|
+
) -> None:
|
|
312
|
+
"""Create embeddings (POST /v1/embeddings)."""
|
|
313
|
+
_ensure_api_credential()
|
|
314
|
+
if encoding_format not in ("float", "base64"):
|
|
315
|
+
typer.echo('encoding_format must be "float" or "base64".', err=True)
|
|
316
|
+
raise typer.Exit(code=1)
|
|
317
|
+
inp: str | list[str] = input_text[0] if len(input_text) == 1 else input_text
|
|
318
|
+
client = _client(base_url, timeout=timeout)
|
|
319
|
+
resp = _call_api(
|
|
320
|
+
lambda: client.create_embeddings(
|
|
321
|
+
model=model,
|
|
322
|
+
input=inp,
|
|
323
|
+
encoding_format=encoding_format, # type: ignore[arg-type]
|
|
324
|
+
dimensions=dimensions,
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
_print(resp.model_dump(), as_json or True)
|
|
328
|
+
|
|
329
|
+
|
|
289
330
|
@auth_app.command("login")
|
|
290
331
|
def auth_login(
|
|
291
332
|
api_key: Optional[str] = typer.Option(
|
|
@@ -434,7 +475,7 @@ def responses_result(
|
|
|
434
475
|
resp = _call_api(lambda: client.get_response(id))
|
|
435
476
|
d = resp.model_dump()
|
|
436
477
|
status = d.get("status") if isinstance(d, dict) else None
|
|
437
|
-
if status in ("completed", "failed", "cancelled"):
|
|
478
|
+
if status in ("completed", "failed", "cancelled", "incomplete"):
|
|
438
479
|
_print(d, True)
|
|
439
480
|
return
|
|
440
481
|
time.sleep(max(0.01, poll_interval))
|
|
@@ -552,7 +593,7 @@ def batch_submit(
|
|
|
552
593
|
window: str = typer.Option(
|
|
553
594
|
"24h",
|
|
554
595
|
"--window",
|
|
555
|
-
help='Batch SLA window: "
|
|
596
|
+
help='Batch SLA window: "24h" is the only supported value.',
|
|
556
597
|
callback=_window_choice,
|
|
557
598
|
),
|
|
558
599
|
base_url: str = typer.Option("https://api.sference.com"),
|
|
@@ -583,7 +624,7 @@ def batch_stream(
|
|
|
583
624
|
window: str = typer.Option(
|
|
584
625
|
"24h",
|
|
585
626
|
"--window",
|
|
586
|
-
help='Batch SLA window: "
|
|
627
|
+
help='Batch SLA window: "24h" is the only supported value.',
|
|
587
628
|
callback=_window_choice,
|
|
588
629
|
),
|
|
589
630
|
poll_interval: float = typer.Option(2.0, "--poll-interval", help="Seconds between status polls while the batch is running."),
|
|
@@ -699,7 +740,7 @@ def stream_create(
|
|
|
699
740
|
window: str = typer.Option(
|
|
700
741
|
"24h",
|
|
701
742
|
"--window",
|
|
702
|
-
help='Per-item SLA window: "
|
|
743
|
+
help='Per-item SLA window: "24h" is the only supported value.',
|
|
703
744
|
callback=_window_choice,
|
|
704
745
|
),
|
|
705
746
|
base_url: str = typer.Option("https://api.sference.com"),
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|