Skip to main content

Open data-platform SDK over Apache Iggy: typed streaming, declared projections and a query DSL, a key-value store, copy-on-write forks, and an optional agent runtime with the Agent Data Exchange Protocol (AGDX).

Project description

laser-sdk (Python)

The LaserData SDK for Python: an open data-platform SDK over Apache Iggy. Native bindings to the Rust SDK via PyO3, so the wire contract, codecs, and runtime are the same ones the Rust client uses.

One Apache Iggy connection gives you typed streaming, declared projections and a query DSL, a key-value store, copy-on-write forks of the read model, and an optional agent runtime with the Agent Data Exchange Protocol (AGDX): publish, request/reply, and a consumer that drives your async def handler with at-least-once delivery, dedup, retry, and a dead-letter queue.

Apache Iggy is the underlying streaming core. Projections, the query layer, the key-value store, and forks are served by LaserData Cloud over that same connection. Against raw Apache Iggy those calls raise UnsupportedError.

Install

pip install laser-sdk

Wheels ship for Linux (x86_64, aarch64) and macOS (Intel, Apple Silicon), Python 3.10 through 3.13.

Connect

import asyncio
from laser_sdk import Laser

async def main():
    laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
    caps = await laser.capabilities()
    print(caps)

asyncio.run(main())

The connection string scheme is optional (iggy:// is assumed). Pin a default stream= so the convenience methods take just a topic, or name the stream per operation with the stream= keyword on each call.

Publish and consume

await laser.ensure_topic("orders", partitions=4)

await (
    laser.publish("orders")
    .index("customer_id", "alice")
    .index("total", "129")
    .inline_payload()
    .json({"id": "o-1", "customer": "alice", "amount": 129})
    .send()
)

Batch and any payload

A single publish is the simplest call, not the common one. publish_batch accumulates records and sends them in one network round-trip, the largest throughput lever the SDK offers, and reads mirror it: a reader cursor drains every record that arrived since the last poll in one call. Batching on both sides is what makes the path efficient.

The payload is yours, in any format. add_json / add_msgpack (and extend_json for a whole list) are conveniences over add_payload, which takes raw bytes the SDK never inspects, so a compressed blob or your own framing rides unchanged. Schema-first Avro and Protobuf bodies are below.

batch = laser.publish_batch("orders").inline_payload()
batch.extend_json([{"id": "o-1", "amount": 129}, {"id": "o-2", "amount": 80}])
batch.add_payload(b"\x00any-bytes-any-format")  # raw bytes, untouched by the SDK
await batch.send()                              # the whole batch, one round-trip

Schema-first bodies (Avro / Protobuf)

Compile a registered writer schema once, then publish raw datums under it. The body is encoded client-side, so a value that stops matching the schema fails before publishing rather than as a managed-side warning you cannot see. The managed plane resolves the schema by id and extracts indexed columns from the binary body.

from laser_sdk import CompiledSchema

source = {"kind": "avro", "schema": fill_avro_schema}
schema_id = await laser.register_schema(source, name="fill")
compiled = CompiledSchema.compile(source, id=schema_id)

batch = laser.publish_batch("trades_avro").inline_payload()
for fill in fills:
    batch = batch.add_avro(compiled, schema_id, fill)
await batch.send()

CompiledSchema also offers validate / validate_value / decode, and the single-record builder has .avro(compiled, schema_id, value). For Protobuf or your own framing, encode the body yourself and ship it with .raw_bytes(bytes, "protobuf") (or batch .add_raw_bytes(..)). Writer schemas live on LaserData Cloud, so registration is a managed feature.

Query (managed)

rows = await (
    laser.query("orders")
    .where_eq("customer_id", "alice")
    .filter_gte("total", 100)
    .order_desc("total")
    .limit(10)
    .with_payload()
    .fetch_all()
)
for row in rows:
    print(row.headers, row.json())

Query, the key-value store, and forks are managed features served by LaserData Cloud. Against raw Apache Iggy they raise UnsupportedError.

Key-value

kv = laser.kv("sessions")
await kv.set("user:42").json({"state": "online"}).ttl(300).send()
state = await kv.get_typed("user:42")
await kv.delete("user:42")

Agents

from laser_sdk import Laser

async def handle(ctx, message):
    text = message.payload.decode()
    await ctx.respond(f"echo: {text}".encode())

laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
await laser.bootstrap(partitions=4)

handle_agent = laser.spawn_agent(
    "echo", "agent.commands", handle, respond_on="agent.responses"
)
await handle_agent.ready()

from laser_sdk import Provenance
reply = await laser.request(
    "agent.commands", "agent.responses", b"hello",
    Provenance(agent="caller"), timeout_secs=10,
)
print(reply.payload.decode())

await handle_agent.shutdown()

For a human-in-the-loop pause, the typed AGDX producer's request_input publishes a prompt and blocks on the human's correlated reply, which a handler resolves with AgentCtx.respond_input:

decision = await laser.agdx("agent.human_input", "orchestrator", conversation_id).request_input(
    "agent.responses", b"approve a $500 refund?", timeout_secs=15
)

Consume and replay

# A resumable reader over a topic. Each poll drains what is new. Persist the
# offsets to resume after a restart.
cursor = laser.reader("orders")
for message in await cursor.poll():
    print(message.json())
saved = cursor.offsets

# Replay a conversation's history off the log (agent runtime).
history = await laser.assemble_context(conversation_id, last_n=50)

Memory and state

Agent memory shares one remember / recall / forget surface over four backends. The log-backed default works on raw Apache Iggy. The in-process vector backend ranks recall by semantic similarity, embedding through your own async def embed(text) -> list[float]. The query and key-value backends are managed.

async def embed(text: str) -> list[float]:
    ...  # your model, or a deterministic stand-in

memory = laser.vector_memory(embed)
await memory.remember("checkout latency traces to the database pool", conversation=cid)
hits = await memory.recall(conversation=cid, semantic="why is checkout slow", limit=3)
print([item.text for item in hits])

# A durable key/value seam for agent state, the same vocabulary as the managed store.
store = ls.InMemoryStore()        # or ls.FileStore("/var/lib/agent")
await store.set("cursor", saved_bytes)
value = await store.get("cursor")

Edge interop (A2A / MCP / AG-UI)

Reach an agent as an A2A task source or an MCP tool server, and render a conversation as AG-UI events, all over the durable log:

# A2A: submit a task, poll for the result.
a2a = laser.a2a_bridge("a2a-gateway", "agent.commands", "agent.responses")
task = await a2a.submit({"message": {"role": "user", "parts": [{"kind": "text", "text": "hi"}]}})
status = await a2a.task(task["id"])

# MCP: advertise tools, route tools/call to the agent.
mcp = laser.mcp_bridge(
    "mcp-gateway", "agent.tool_calls", "agent.tool_results", "laser-mcp",
    tools=[{"name": "ask", "input_schema": {"type": "object"}}],
)
tools = mcp.list_tools()
result = await mcp.call_tool("ask", {"q": "what is AGDX?"})

# An agent answers a bridge request from its handler:
async def handle(ctx, message):
    await ctx.respond_input("agent.responses", b"the answer")

# AG-UI: snapshot + deltas reconstruct shared state off the log.
await laser.publish_state_snapshot("agent.llm_io", "ui", conversation_id, {"count": 1})
state = await laser.reconstruct_state(conversation_id, "agent.llm_io")
events = await laser.agui_events(conversation_id, "agent.llm_io")

Host the actual HTTP endpoint with your Python web framework over these adapter methods.

Errors

Every failure raises a subclass of LaserError: QueryError, KvError, ForkError, UnsupportedError, InvalidError, CodecError, ProtocolError, TimeoutError, ConfigError, TransportError. Each instance carries code, retryable, unsupported, not_found, version_skew, version_conflict, and stale attributes so you can branch without matching on the type.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

laser_sdk-0.0.1rc1.tar.gz (332.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.0 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (10.1 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

laser_sdk-0.0.1rc1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (18.8 MB view details)

Uploaded CPython 3.10+macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

File details

Details for the file laser_sdk-0.0.1rc1.tar.gz.

File metadata

  • Download URL: laser_sdk-0.0.1rc1.tar.gz
  • Upload date:
  • Size: 332.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for laser_sdk-0.0.1rc1.tar.gz
Algorithm Hash digest
SHA256 2a622d6c8ba07059b1f6b48602a375a7647a6aa3303f1f3365386be7e77fad09
MD5 68b11d04a3d2f8ba7e0f9bc8fca16f69
BLAKE2b-256 cc384bdbc61b2403aaedabff8c6c14c2ba4128e4a8e02ca57de3843f3b5a71f7

See more details on using hashes here.

Provenance

The following attestation bundles were made for laser_sdk-0.0.1rc1.tar.gz:

Publisher: ci-python.yml on laserdata/laser-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a55d32072f28a2a81efefad0f26beb2138379c9195f04b9d207e29ab97cce680
MD5 13a1140dd34f93c1a787520f04b3da02
BLAKE2b-256 53d7c97fa9b49343b96f2cb6ae4f19a6933f9ee66702259a4b7e53353836a9c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: ci-python.yml on laserdata/laser-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 541a96ded033f621b5f44f544d667495a244c7c19eb25dd5b4c77ac58001cb3c
MD5 42e4a6fa62cca7e03562189de585e7a1
BLAKE2b-256 0e0e7c5b293b766076fff8a3db35813bb15410e1f64a603a7aa5b9b40ef478f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for laser_sdk-0.0.1rc1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: ci-python.yml on laserdata/laser-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file laser_sdk-0.0.1rc1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for laser_sdk-0.0.1rc1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 74c363b7f5e46b0756a8e147f117b06d648ff893eda42b1efd94e120fac070df
MD5 1540d86f247bdbab0886af8ccfc8de54
BLAKE2b-256 7691a6683a74a0b9fe53ee06e9175abaeb5d3bc8709e9e1aa0774c53f11a72a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for laser_sdk-0.0.1rc1-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl:

Publisher: ci-python.yml on laserdata/laser-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page