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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sference-cli
3
- Version: 0.1.4
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.4
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` `15m`/`1h`/`24h`) |
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` `15m`/`1h`/`24h`, `--json`) |
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` `15m`/`1h`/`24h`) |
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` `15m`/`1h`/`24h`, `--json`) |
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.4"
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.4",
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: "15m", "1h", or "24h".',
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: "15m", "1h", or "24h".',
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: "15m", "1h", or "24h" (default for items in this stream).',
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