Sessions
Almost every studio has a notion of a working session: the prompt you were refining, the seed you liked, the takes you made along the way. helmstudio makes that a platform concept, so no studio has to invent its own, and every studio's sessions have the same shape.
A session is a name and a state document that is entirely the studio's. This studio holds kv, assets and gallery:
"""Keep a working session: its state, and the outputs made during it.
Run under helmstudio or helm dev by a studio holding `kv`, `assets` and
`gallery`.
"""
import os
from helm_runtime_sdk import HelmError, from_env
helm = from_env()
# A session holds whatever the studio's own interface needs to come back to.
session = helm.sessions.create({"name": "lighthouse series", "state": {"prompt": "a lighthouse", "seed": 7}})
# An output made during it says so.
path = os.path.join(os.environ["HELM_STAGE_DIR"], "session-take.png")
with open(path, "wb") as f:
f.write(bytes.fromhex(
"89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489"
"0000000d4944415478da63f8cfc0f01f0005000201ddb1c61c0000000049454e44ae426082"))
asset = helm.assets.adopt({"path": path, "kind": "image"})
helm.gallery.add({"kind": "image", "asset_id": asset["id"], "session_id": session["id"],
"params": {"prompt": "a lighthouse", "seed": 7}})
found = helm.gallery.query(session_id=session["id"])
assert len(found["items"]) == 1, found
# State changes as a merge patch, against the etag read: a second tab editing
# the same session cannot overwrite this one without seeing it.
session = helm.sessions.update(session["id"], {"state": {"seed": 8}}, if_match=session["etag"])
assert session["state"] == {"prompt": "a lighthouse", "seed": 8}, session["state"]
try:
helm.sessions.update(session["id"], {"state": {"seed": 9}}, if_match="stale")
raise SystemExit("a stale etag was accepted")
except HelmError as e:
assert e.kind == "Conflict", e.kind
# Try something else without losing where you were.
copy = helm.sessions.duplicate(session["id"], {"name": "lighthouse series, at night"})
assert copy["state"] == session["state"], copy
print("ok")
State belongs to the studio
helmstudio never reads state. Put in it whatever the studio's page needs to come back to where the person left off.
Changes are merge patches, against what you read
update applies a JSON merge patch: the fields you send replace those in the document, and the rest are kept. Every read returns an etag; pass it as if_match, and an update made against a document someone else has changed since — a second tab, say — is refused as a Conflict rather than silently overwriting theirs. Read it again, merge, and retry.
Items made during a session say so
A gallery item recorded with a session_id belongs to that session, and gallery.query(session_id=…) finds them.
Duplicate, rather than lose your place
duplicate copies a session's state under a new name, so trying something else costs nothing. Deleting a session is a soft delete: its name becomes free again, and the items made during it keep their session_id.