Skip to content

Latest commit

 

History

History
61 lines (52 loc) · 2.81 KB

README.md

File metadata and controls

61 lines (52 loc) · 2.81 KB

Python client

Install with pip install ./clients/python, beside an installed polylogue CLI. The client needs only Python's standard library at runtime. It invokes CLI JSON with an argument list and uses the same daemon as other clients.

from polylogue.client import Client, Refused
import shlex

client = Client()  # Or Client("/path/to/archive", executable="/path/to/polylogue")
page = client.query("messages where parser", page_size=100)
rows = page.data["value"]["rows"]
if page.data["value"].get("next") is not None:
    following = client.query("messages where parser", cursor=page.data["value"]["next"], page_size=100)

try:
    session = client.read("session:claude-code:example")
    ready = session.json()["value"]["document"]["footer"].get("next")
    if ready is not None:
        words = shlex.split(ready["cli"], posix=True)
        if not words or words[0] != "polylogue":
            raise ValueError("unexpected ReadyCall product")
        following = client.call(*words[1:])
except Refused as error:
    print(error.kind, error.answer.json())

polylogue.models.Answer is frozen, including its nested maps and lists. answer.json() returns an independent ordinary JSON value. All fields, nulls, integer precision and complete refusals survive. Ordinary calls retain the whole shared outcome/value envelope. Empty and degraded answers retain their payloads; refusals expose the complete error answer. Query cursors belong to query pages. Read continuations execute the complete generated request, including its original arguments, cursor and deadline. Use client.read(identity, page_tokens=600) to choose the number of tokens transferred in one page.

client.call(*arguments) takes the same words as a CLI command, without polylogue --json. It covers the other declared operations. A write is sent once. For retries, give the same --request-id and identical arguments; the client never invents a second write after a lost answer. An explicit archive is passed as the CLI's --archive argument for ordinary calls and change feeds.

for line in client.changes(previous_position):
    record = line.data
    if record["type"] == "begin" and record["replacement"]:
        clear_local_view()
    elif record["type"] == "change":
        apply_change(record["component"], record["change"])
    elif record["type"] == "complete":
        save_position(record["position"])

Save a position only after applying the earlier lines in that batch. An error or interrupted iterator leaves the previous position in force; a new index generation asks the consumer to replace its local view. Breaking out early requires closing the iterator (for example with contextlib.closing).

Contract tests run through the repository's check operation: a real daemon and CLI over a temporary archive are compared with the Python client.