From cf1308b501879009b8c9c363f842c22af56928ca Mon Sep 17 00:00:00 2001 From: Jonathan Berg Date: Fri, 16 Oct 2026 12:18:22 -0700 Subject: [PATCH] Update docs to reference new cloud decision models and support images --- README.md | 19 ++++++++++++++----- ollama/_client.py | 12 ++++++++++-- ollama/_types.py | 2 ++ tests/test_systemone.py | 22 ++++++++++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9f72ba63..3038d7ce 100644 --- a/README.md +++ b/README.md @@ -274,16 +274,25 @@ response = ollama.systemone( print(response.answers['team']) ``` -System One uses `POST /v1/systemone` and requires Ollama v0.35.0 or later with a -compatible local model such as `nimble`. It returns one JSON response; streaming -and cloud models are not supported. +System One uses `POST /v1/systemone` and returns one JSON response; streaming is +not supported. It runs locally with decision models such as `nimble` (Ollama +v0.35.0 or later) or `clef` (v0.35.1 or later), and in the cloud with `clef:cloud` +on a paid plan (through Ollama v0.40.5 or later, or [directly against +ollama.com](#cloud-api-ollamacom)). + +Clef also reads images (v0.40.0 or later locally): pass `images` as file paths, +bytes, or base64 strings, shared by all questions. Cloud requests accept up to 4 +PNG, JPEG, or WebP images (each at most 4 MiB and 16 megapixels, 8 MiB total). `state` and question `instructions` accept text, JSON objects, or arrays. Questions are evaluated in their supplied order: -- `choice`: 2–26 option keys mapped to descriptions; `None` uses the key as its description. +- `choice`: 2–26 option keys mapped to descriptions (up to 255 in the cloud); `None` uses the key as its description. - `noul`: probability of true, with optional `{"false": "No", "true": "Yes"}` descriptions. -- `score`: 2–26 descriptions ordered lowest to highest; returns a potentially fractional, zero-based score. +- `score`: 2–10 descriptions ordered lowest to highest; returns a potentially fractional, zero-based score. + +In the cloud, question ids may only contain ASCII letters, digits, `_`, `.`, and +`-`, up to 100 characters, and a request may ask up to 64 questions. Responses contain `model`, `answers`, and `usage.input_tokens` / `usage.output_tokens`. Confidence measures probability concentration, not calibrated correctness. diff --git a/ollama/_client.py b/ollama/_client.py index 13dd6441..3654e3c0 100644 --- a/ollama/_client.py +++ b/ollama/_client.py @@ -413,8 +413,11 @@ def systemone( state: SystemOneContent, questions: Mapping[str, Union[SystemOneQuestion, Mapping[str, Any]]], keep_alive: Optional[Union[float, str]] = None, + images: Optional[Sequence[Union[str, bytes, Image]]] = None, ) -> SystemOneResponse: - """Score choice, noul, and score questions with a local System One model. + """Score choice, noul, and score questions with a System One decision model. + + `images` are shared by all questions, in order; only models that accept images (such as Clef) support them. Returns one JSON response. Streaming is not supported. """ @@ -425,6 +428,7 @@ def systemone( json=SystemOneRequest( model=model, state=state, + images=list(_copy_images(images)) if images else None, questions=questions, keep_alive=keep_alive, ).model_dump(exclude_none=True), @@ -1069,8 +1073,11 @@ async def systemone( state: SystemOneContent, questions: Mapping[str, Union[SystemOneQuestion, Mapping[str, Any]]], keep_alive: Optional[Union[float, str]] = None, + images: Optional[Sequence[Union[str, bytes, Image]]] = None, ) -> SystemOneResponse: - """Score choice, noul, and score questions with a local System One model. + """Score choice, noul, and score questions with a System One decision model. + + `images` are shared by all questions, in order; only models that accept images (such as Clef) support them. Returns one JSON response. Streaming is not supported. """ @@ -1081,6 +1088,7 @@ async def systemone( json=SystemOneRequest( model=model, state=state, + images=list(_copy_images(images)) if images else None, questions=questions, keep_alive=keep_alive, ).model_dump(exclude_none=True), diff --git a/ollama/_types.py b/ollama/_types.py index cf7264b5..ad041013 100644 --- a/ollama/_types.py +++ b/ollama/_types.py @@ -648,6 +648,8 @@ class SystemOneScoreQuestion(SubscriptableBaseModel): class SystemOneRequest(SubscriptableBaseModel): model: str state: SystemOneContent + images: Optional[Sequence[Image]] = None + 'Images shared by all questions; base64 PNG, JPEG, or WebP.' questions: Dict[str, SystemOneQuestion] keep_alive: Optional[Union[float, str]] = None diff --git a/tests/test_systemone.py b/tests/test_systemone.py index 941a047b..1e256870 100644 --- a/tests/test_systemone.py +++ b/tests/test_systemone.py @@ -1,3 +1,4 @@ +import base64 import inspect import json @@ -86,3 +87,24 @@ def handle(request): await response assert error.value.status_code == status assert error.value.error == message + + +@pytest.mark.anyio +@pytest.mark.parametrize('client_type', [ollama.Client, ollama.AsyncClient]) +async def test_systemone_images(client_type, tmp_path): + png = b'\x89PNG\r\n\x1a\nsynthetic' + path = tmp_path / 'ticket.png' + path.write_bytes(png) + encoded = base64.b64encode(png).decode() + + def handle(request): + body = json.loads(request.content) + assert body['images'] == [encoded] * 4 + assert list(body) == ['model', 'state', 'images', 'questions'] + return httpx.Response(200, json={'model': 'clef', 'answers': {'refund': {'type': 'noul', 'noul': 0.5}}, 'usage': {'input_tokens': 1, 'output_tokens': 0}}) + + client = client_type(transport=httpx.MockTransport(handle)) + response = client.systemone('clef', 'See screenshot', {'refund': {'type': 'noul', 'instructions': 'Refund?'}}, images=[png, encoded, str(path), ollama.Image(value=path)]) + if inspect.isawaitable(response): + response = await response + assert response.answers['refund'].noul == 0.5