laser-sdk 0.0.1rc1__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.
Files changed (196) hide show
  1. laser_sdk-0.0.1rc1/Cargo.toml +49 -0
  2. laser_sdk-0.0.1rc1/PKG-INFO +247 -0
  3. laser_sdk-0.0.1rc1/README.md +221 -0
  4. laser_sdk-0.0.1rc1/foreign/python/.gitignore +6 -0
  5. laser_sdk-0.0.1rc1/foreign/python/Cargo.lock +4893 -0
  6. laser_sdk-0.0.1rc1/foreign/python/Cargo.toml +47 -0
  7. laser_sdk-0.0.1rc1/foreign/python/README.md +221 -0
  8. laser_sdk-0.0.1rc1/foreign/python/laser_sdk.pyi +1276 -0
  9. laser_sdk-0.0.1rc1/foreign/python/src/agdx.rs +240 -0
  10. laser_sdk-0.0.1rc1/foreign/python/src/agent.rs +437 -0
  11. laser_sdk-0.0.1rc1/foreign/python/src/agent_runtime.rs +508 -0
  12. laser_sdk-0.0.1rc1/foreign/python/src/bin/stub_gen.rs +40 -0
  13. laser_sdk-0.0.1rc1/foreign/python/src/client.rs +190 -0
  14. laser_sdk-0.0.1rc1/foreign/python/src/convert.rs +78 -0
  15. laser_sdk-0.0.1rc1/foreign/python/src/errors.rs +129 -0
  16. laser_sdk-0.0.1rc1/foreign/python/src/fork.rs +221 -0
  17. laser_sdk-0.0.1rc1/foreign/python/src/interop.rs +327 -0
  18. laser_sdk-0.0.1rc1/foreign/python/src/kv.rs +546 -0
  19. laser_sdk-0.0.1rc1/foreign/python/src/lib.rs +61 -0
  20. laser_sdk-0.0.1rc1/foreign/python/src/memory.rs +334 -0
  21. laser_sdk-0.0.1rc1/foreign/python/src/publish.rs +486 -0
  22. laser_sdk-0.0.1rc1/foreign/python/src/query.rs +730 -0
  23. laser_sdk-0.0.1rc1/foreign/python/src/reader.rs +128 -0
  24. laser_sdk-0.0.1rc1/foreign/python/src/schema.rs +87 -0
  25. laser_sdk-0.0.1rc1/foreign/python/src/state_store.rs +109 -0
  26. laser_sdk-0.0.1rc1/foreign/python/tests/conftest.py +65 -0
  27. laser_sdk-0.0.1rc1/foreign/python/tests/test_integration.py +327 -0
  28. laser_sdk-0.0.1rc1/foreign/python/tests/test_smoke.py +100 -0
  29. laser_sdk-0.0.1rc1/laser_sdk.pyi +1276 -0
  30. laser_sdk-0.0.1rc1/pyproject.toml +51 -0
  31. laser_sdk-0.0.1rc1/sdk/Cargo.lock +7 -0
  32. laser_sdk-0.0.1rc1/sdk/Cargo.toml +103 -0
  33. laser_sdk-0.0.1rc1/sdk/LICENSE +201 -0
  34. laser_sdk-0.0.1rc1/sdk/NOTICE +13 -0
  35. laser_sdk-0.0.1rc1/sdk/README.md +117 -0
  36. laser_sdk-0.0.1rc1/sdk/src/a2a.rs +528 -0
  37. laser_sdk-0.0.1rc1/sdk/src/agent/agdx.rs +637 -0
  38. laser_sdk-0.0.1rc1/sdk/src/agent/assembler.rs +318 -0
  39. laser_sdk-0.0.1rc1/sdk/src/agent/builder.rs +121 -0
  40. laser_sdk-0.0.1rc1/sdk/src/agent/consumer.rs +639 -0
  41. laser_sdk-0.0.1rc1/sdk/src/agent/ctx.rs +143 -0
  42. laser_sdk-0.0.1rc1/sdk/src/agent/laser.rs +402 -0
  43. laser_sdk-0.0.1rc1/sdk/src/agent/mod.rs +26 -0
  44. laser_sdk-0.0.1rc1/sdk/src/agent/router.rs +61 -0
  45. laser_sdk-0.0.1rc1/sdk/src/agent/session.rs +42 -0
  46. laser_sdk-0.0.1rc1/sdk/src/agent/state.rs +31 -0
  47. laser_sdk-0.0.1rc1/sdk/src/agui.rs +369 -0
  48. laser_sdk-0.0.1rc1/sdk/src/capabilities.rs +286 -0
  49. laser_sdk-0.0.1rc1/sdk/src/context.rs +219 -0
  50. laser_sdk-0.0.1rc1/sdk/src/cursor.rs +153 -0
  51. laser_sdk-0.0.1rc1/sdk/src/error.rs +230 -0
  52. laser_sdk-0.0.1rc1/sdk/src/fork/client.rs +344 -0
  53. laser_sdk-0.0.1rc1/sdk/src/fork/mod.rs +13 -0
  54. laser_sdk-0.0.1rc1/sdk/src/kv/client.rs +606 -0
  55. laser_sdk-0.0.1rc1/sdk/src/kv/mod.rs +20 -0
  56. laser_sdk-0.0.1rc1/sdk/src/laser.rs +792 -0
  57. laser_sdk-0.0.1rc1/sdk/src/lib.rs +39 -0
  58. laser_sdk-0.0.1rc1/sdk/src/mcp.rs +547 -0
  59. laser_sdk-0.0.1rc1/sdk/src/memory.rs +852 -0
  60. laser_sdk-0.0.1rc1/sdk/src/message.rs +16 -0
  61. laser_sdk-0.0.1rc1/sdk/src/poll.rs +50 -0
  62. laser_sdk-0.0.1rc1/sdk/src/prelude.rs +60 -0
  63. laser_sdk-0.0.1rc1/sdk/src/provenance/keys.rs +8 -0
  64. laser_sdk-0.0.1rc1/sdk/src/provenance/mod.rs +13 -0
  65. laser_sdk-0.0.1rc1/sdk/src/provenance/runtime.rs +439 -0
  66. laser_sdk-0.0.1rc1/sdk/src/provenance/topic.rs +83 -0
  67. laser_sdk-0.0.1rc1/sdk/src/query/client.rs +1745 -0
  68. laser_sdk-0.0.1rc1/sdk/src/query/mod.rs +54 -0
  69. laser_sdk-0.0.1rc1/sdk/src/query/record.rs +315 -0
  70. laser_sdk-0.0.1rc1/sdk/src/schema_codecs.rs +370 -0
  71. laser_sdk-0.0.1rc1/sdk/src/state_store.rs +154 -0
  72. laser_sdk-0.0.1rc1/sdk/src/types/ids.rs +423 -0
  73. laser_sdk-0.0.1rc1/sdk/src/types/mod.rs +3 -0
  74. laser_sdk-0.0.1rc1/sdk/tests/integration/a2a.rs +167 -0
  75. laser_sdk-0.0.1rc1/sdk/tests/integration/agdx_consume.rs +76 -0
  76. laser_sdk-0.0.1rc1/sdk/tests/integration/agdx_stream.rs +57 -0
  77. laser_sdk-0.0.1rc1/sdk/tests/integration/agui.rs +136 -0
  78. laser_sdk-0.0.1rc1/sdk/tests/integration/context.rs +68 -0
  79. laser_sdk-0.0.1rc1/sdk/tests/integration/deadletter.rs +97 -0
  80. laser_sdk-0.0.1rc1/sdk/tests/integration/fanout.rs +70 -0
  81. laser_sdk-0.0.1rc1/sdk/tests/integration/handoff.rs +87 -0
  82. laser_sdk-0.0.1rc1/sdk/tests/integration/harness.rs +71 -0
  83. laser_sdk-0.0.1rc1/sdk/tests/integration/human_input.rs +121 -0
  84. laser_sdk-0.0.1rc1/sdk/tests/integration/iggy_container.rs +72 -0
  85. laser_sdk-0.0.1rc1/sdk/tests/integration/main.rs +27 -0
  86. laser_sdk-0.0.1rc1/sdk/tests/integration/managed_unsupported.rs +185 -0
  87. laser_sdk-0.0.1rc1/sdk/tests/integration/mcp.rs +124 -0
  88. laser_sdk-0.0.1rc1/sdk/tests/integration/memory.rs +94 -0
  89. laser_sdk-0.0.1rc1/sdk/tests/integration/provenance.rs +48 -0
  90. laser_sdk-0.0.1rc1/sdk/tests/integration/reliable.rs +294 -0
  91. laser_sdk-0.0.1rc1/sdk/tests/integration/replay.rs +314 -0
  92. laser_sdk-0.0.1rc1/sdk/tests/integration/request.rs +70 -0
  93. laser_sdk-0.0.1rc1/sdk/tests/integration/session.rs +40 -0
  94. laser_sdk-0.0.1rc1/sdk/tests/integration/shutdown.rs +53 -0
  95. laser_sdk-0.0.1rc1/sdk/tests/integration/state.rs +56 -0
  96. laser_sdk-0.0.1rc1/sdk/tests/integration/warm_dedup.rs +107 -0
  97. laser_sdk-0.0.1rc1/wire/Cargo.toml +74 -0
  98. laser_sdk-0.0.1rc1/wire/LICENSE +201 -0
  99. laser_sdk-0.0.1rc1/wire/NOTICE +13 -0
  100. laser_sdk-0.0.1rc1/wire/README.md +59 -0
  101. laser_sdk-0.0.1rc1/wire/fixtures/agent_body_ref.bin +0 -0
  102. laser_sdk-0.0.1rc1/wire/fixtures/agent_card.bin +1 -0
  103. laser_sdk-0.0.1rc1/wire/fixtures/agent_chunk.bin +0 -0
  104. laser_sdk-0.0.1rc1/wire/fixtures/agent_chunk_open.bin +0 -0
  105. laser_sdk-0.0.1rc1/wire/fixtures/agent_chunk_terminal.bin +0 -0
  106. laser_sdk-0.0.1rc1/wire/fixtures/agent_command.bin +0 -0
  107. laser_sdk-0.0.1rc1/wire/fixtures/agent_dead_letter.bin +0 -0
  108. laser_sdk-0.0.1rc1/wire/fixtures/agent_error.bin +0 -0
  109. laser_sdk-0.0.1rc1/wire/fixtures/agent_error_body.bin +1 -0
  110. laser_sdk-0.0.1rc1/wire/fixtures/agent_event.bin +0 -0
  111. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_chunk_late_deadline.bin +0 -0
  112. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_chunk_no_sequence.bin +0 -0
  113. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_chunk_open_no_operation.bin +0 -0
  114. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_command_no_correlation.bin +0 -0
  115. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_error_last.bin +0 -0
  116. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_event_task_state.bin +0 -0
  117. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_response_channel.bin +0 -0
  118. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_status_bad_operation.bin +0 -0
  119. laser_sdk-0.0.1rc1/wire/fixtures/agent_invalid_status_no_operation.bin +0 -0
  120. laser_sdk-0.0.1rc1/wire/fixtures/agent_must_understand.bin +0 -0
  121. laser_sdk-0.0.1rc1/wire/fixtures/agent_record.bin +0 -0
  122. laser_sdk-0.0.1rc1/wire/fixtures/agent_response.bin +0 -0
  123. laser_sdk-0.0.1rc1/wire/fixtures/agent_signature.bin +1 -0
  124. laser_sdk-0.0.1rc1/wire/fixtures/agent_status_card.bin +0 -0
  125. laser_sdk-0.0.1rc1/wire/fixtures/agent_status_task.bin +0 -0
  126. laser_sdk-0.0.1rc1/wire/fixtures/backend_announce.bin +1 -0
  127. laser_sdk-0.0.1rc1/wire/fixtures/browse_projections.json +62 -0
  128. laser_sdk-0.0.1rc1/wire/fixtures/browse_reply_decoded.bin +1 -0
  129. laser_sdk-0.0.1rc1/wire/fixtures/browse_reply_projections.bin +0 -0
  130. laser_sdk-0.0.1rc1/wire/fixtures/browse_reply_schema_registered.bin +1 -0
  131. laser_sdk-0.0.1rc1/wire/fixtures/browse_reply_schemas.bin +0 -0
  132. laser_sdk-0.0.1rc1/wire/fixtures/browse_schemas.json +40 -0
  133. laser_sdk-0.0.1rc1/wire/fixtures/capabilities.json +17 -0
  134. laser_sdk-0.0.1rc1/wire/fixtures/control_apply_binding.bin +0 -0
  135. laser_sdk-0.0.1rc1/wire/fixtures/control_drop_schema.bin +0 -0
  136. laser_sdk-0.0.1rc1/wire/fixtures/control_register_projection.bin +0 -0
  137. laser_sdk-0.0.1rc1/wire/fixtures/control_register_schema_avro.bin +0 -0
  138. laser_sdk-0.0.1rc1/wire/fixtures/control_register_schema_json.bin +0 -0
  139. laser_sdk-0.0.1rc1/wire/fixtures/control_register_schema_protobuf.bin +0 -0
  140. laser_sdk-0.0.1rc1/wire/fixtures/control_remove_binding.bin +0 -0
  141. laser_sdk-0.0.1rc1/wire/fixtures/decode_record.bin +0 -0
  142. laser_sdk-0.0.1rc1/wire/fixtures/error_body.json +7 -0
  143. laser_sdk-0.0.1rc1/wire/fixtures/fork_create.bin +1 -0
  144. laser_sdk-0.0.1rc1/wire/fixtures/fork_info.json +9 -0
  145. laser_sdk-0.0.1rc1/wire/fixtures/fork_put.bin +1 -0
  146. laser_sdk-0.0.1rc1/wire/fixtures/fork_reply_created.bin +0 -0
  147. laser_sdk-0.0.1rc1/wire/fixtures/forwarded_command.bin +0 -0
  148. laser_sdk-0.0.1rc1/wire/fixtures/forwarded_query.bin +1 -0
  149. laser_sdk-0.0.1rc1/wire/fixtures/hello_reply.bin +1 -0
  150. laser_sdk-0.0.1rc1/wire/fixtures/hello_reply_agent.bin +1 -0
  151. laser_sdk-0.0.1rc1/wire/fixtures/hello_reply_features.bin +1 -0
  152. laser_sdk-0.0.1rc1/wire/fixtures/kv_cas.bin +1 -0
  153. laser_sdk-0.0.1rc1/wire/fixtures/kv_namespaces.bin +1 -0
  154. laser_sdk-0.0.1rc1/wire/fixtures/kv_page_view.json +10 -0
  155. laser_sdk-0.0.1rc1/wire/fixtures/kv_reply_committed.bin +1 -0
  156. laser_sdk-0.0.1rc1/wire/fixtures/kv_reply_namespaces.bin +1 -0
  157. laser_sdk-0.0.1rc1/wire/fixtures/kv_reply_page.bin +0 -0
  158. laser_sdk-0.0.1rc1/wire/fixtures/kv_reply_version_conflict.bin +1 -0
  159. laser_sdk-0.0.1rc1/wire/fixtures/kv_scan.bin +1 -0
  160. laser_sdk-0.0.1rc1/wire/fixtures/kv_set.bin +0 -0
  161. laser_sdk-0.0.1rc1/wire/fixtures/query_envelope.bin +0 -0
  162. laser_sdk-0.0.1rc1/wire/fixtures/query_envelope_aggregate.bin +0 -0
  163. laser_sdk-0.0.1rc1/wire/fixtures/query_envelope_raw_sql.bin +0 -0
  164. laser_sdk-0.0.1rc1/wire/fixtures/query_envelope_read_your_writes.bin +0 -0
  165. laser_sdk-0.0.1rc1/wire/fixtures/query_reply_err_stale.bin +1 -0
  166. laser_sdk-0.0.1rc1/wire/fixtures/query_reply_err_too_large.bin +1 -0
  167. laser_sdk-0.0.1rc1/wire/fixtures/query_reply_ok.bin +0 -0
  168. laser_sdk-0.0.1rc1/wire/fixtures/query_result.json +36 -0
  169. laser_sdk-0.0.1rc1/wire/fixtures/register_schema_managed.bin +1 -0
  170. laser_sdk-0.0.1rc1/wire/fixtures/schema_def.json +7 -0
  171. laser_sdk-0.0.1rc1/wire/src/agent.rs +2232 -0
  172. laser_sdk-0.0.1rc1/wire/src/browse.rs +181 -0
  173. laser_sdk-0.0.1rc1/wire/src/codecs.rs +284 -0
  174. laser_sdk-0.0.1rc1/wire/src/codes.rs +101 -0
  175. laser_sdk-0.0.1rc1/wire/src/commands.rs +78 -0
  176. laser_sdk-0.0.1rc1/wire/src/content.rs +122 -0
  177. laser_sdk-0.0.1rc1/wire/src/control.rs +1039 -0
  178. laser_sdk-0.0.1rc1/wire/src/encoding.rs +197 -0
  179. laser_sdk-0.0.1rc1/wire/src/error.rs +30 -0
  180. laser_sdk-0.0.1rc1/wire/src/fixtures.rs +114 -0
  181. laser_sdk-0.0.1rc1/wire/src/fork.rs +269 -0
  182. laser_sdk-0.0.1rc1/wire/src/forward.rs +123 -0
  183. laser_sdk-0.0.1rc1/wire/src/framing.rs +129 -0
  184. laser_sdk-0.0.1rc1/wire/src/headers.rs +82 -0
  185. laser_sdk-0.0.1rc1/wire/src/hello.rs +196 -0
  186. laser_sdk-0.0.1rc1/wire/src/http.rs +560 -0
  187. laser_sdk-0.0.1rc1/wire/src/http_client.rs +830 -0
  188. laser_sdk-0.0.1rc1/wire/src/kv.rs +420 -0
  189. laser_sdk-0.0.1rc1/wire/src/lib.rs +54 -0
  190. laser_sdk-0.0.1rc1/wire/src/limits.rs +98 -0
  191. laser_sdk-0.0.1rc1/wire/src/query.rs +846 -0
  192. laser_sdk-0.0.1rc1/wire/src/result.rs +268 -0
  193. laser_sdk-0.0.1rc1/wire/src/topics.rs +13 -0
  194. laser_sdk-0.0.1rc1/wire/tests/constants.rs +187 -0
  195. laser_sdk-0.0.1rc1/wire/tests/robustness.rs +123 -0
  196. laser_sdk-0.0.1rc1/wire/tests/wire_fixtures.rs +1007 -0
@@ -0,0 +1,49 @@
1
+ [workspace]
2
+ exclude = ["bdd/rust", "foreign/python", "fuzz"]
3
+ members = ["examples/rust", "sdk", "wire"]
4
+ resolver = "2"
5
+
6
+ [workspace.package]
7
+ edition = "2024"
8
+ license = "Apache-2.0"
9
+ repository = "https://github.com/laserdata/laser-sdk"
10
+ rust-version = "1.96"
11
+ version = "0.0.1-rc.2"
12
+
13
+ [workspace.dependencies]
14
+ apache-avro = { version = "0.21.0" }
15
+ async-trait = { version = "0.1.89" }
16
+ axum = { version = "0.8.9" }
17
+ bon = { version = "3.9.3" }
18
+ bson = { version = "3.1.0", features = ["serde"] }
19
+ bytes = { version = "1.12.0" }
20
+ ciborium = { version = "0.2.2" }
21
+ colored = { version = "3.1.1" }
22
+ dashmap = { version = "6.2.1" }
23
+ dtor = { version = "1.0" }
24
+ futures = { version = "0.3.32" }
25
+ iggy = { version = "0.10.1-edge.2" }
26
+ json-patch = { version = "4.2.0" }
27
+ jsonschema = { version = "0.46.5", default-features = false }
28
+ laser-sdk = { path = "sdk" }
29
+ laser-wire = { path = "wire", version = "=0.0.1-rc.2" }
30
+ prost = { version = "0.14.4" }
31
+ prost-reflect = { version = "0.16.4", features = ["serde"] }
32
+ protox = { version = "0.9.1" }
33
+ reqwest = { version = "0.13.4", default-features = false, features = ["json", "rustls"] }
34
+ rmp-serde = { version = "1.3.1" }
35
+ serde = { version = "1.0", features = ["derive"] }
36
+ serde_json = { version = "1.0" }
37
+ serde_urlencoded = { version = "0.7.1" }
38
+ strum = { version = "0.28.0", features = ["derive"] }
39
+ tempfile = { version = "3.27.0" }
40
+ testcontainers-modules = { version = "0.15.0", features = ["http_wait"] }
41
+ thiserror = { version = "2.0.18" }
42
+ # Transitive of bson, bounded because bson 3.1.0 does not compile against time 0.3.48 (conflicting From impls).
43
+ # Used only by the wire crate's `bson` feature, drop the bound once a fixed bson ships.
44
+ time = { version = ">=0.3.36, <0.3.48", default-features = false }
45
+ tokio = { version = "1.52.3", features = ["fs", "macros", "rt", "rt-multi-thread", "sync", "time"] }
46
+ tracing = { version = "0.1.44" }
47
+ tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
48
+ trait-variant = { version = "0.1.2" }
49
+ ulid = { version = "1.2.1" }
@@ -0,0 +1,247 @@
1
+ Metadata-Version: 2.4
2
+ Name: laser-sdk
3
+ Version: 0.0.1rc1
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: 3 :: Only
7
+ Classifier: License :: OSI Approved :: Apache Software License
8
+ Classifier: Topic :: Database
9
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
10
+ Requires-Dist: pytest>=8.0,<9.0 ; extra == 'testing'
11
+ Requires-Dist: pytest-asyncio>=0.24,<2.0 ; extra == 'testing'
12
+ Requires-Dist: pytest-bdd>=8.0,<9.0 ; extra == 'testing'
13
+ Requires-Dist: pytest-timeout>=2.0,<3.0 ; extra == 'testing'
14
+ Requires-Dist: ruff>=0.6,<1.0 ; extra == 'testing'
15
+ Requires-Dist: testcontainers>=4.0,<5.0 ; extra == 'testing'
16
+ Provides-Extra: testing
17
+ Summary: 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).
18
+ Keywords: laserdata,iggy,streaming,agents,agentic,ai
19
+ Author: LaserData
20
+ License: Apache-2.0
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
23
+ Project-URL: Homepage, https://laserdata.com
24
+ Project-URL: Repository, https://github.com/laserdata/laser-sdk
25
+
26
+ # laser-sdk (Python)
27
+
28
+ 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.
29
+
30
+ 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.
31
+
32
+ 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`.
33
+
34
+ ## Install
35
+
36
+ ```
37
+ pip install laser-sdk
38
+ ```
39
+
40
+ Wheels ship for Linux (x86_64, aarch64) and macOS (Intel, Apple Silicon), Python 3.10 through 3.13.
41
+
42
+ ## Connect
43
+
44
+ ```python
45
+ import asyncio
46
+ from laser_sdk import Laser
47
+
48
+ async def main():
49
+ laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
50
+ caps = await laser.capabilities()
51
+ print(caps)
52
+
53
+ asyncio.run(main())
54
+ ```
55
+
56
+ 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.
57
+
58
+ ## Publish and consume
59
+
60
+ ```python
61
+ await laser.ensure_topic("orders", partitions=4)
62
+
63
+ await (
64
+ laser.publish("orders")
65
+ .index("customer_id", "alice")
66
+ .index("total", "129")
67
+ .inline_payload()
68
+ .json({"id": "o-1", "customer": "alice", "amount": 129})
69
+ .send()
70
+ )
71
+ ```
72
+
73
+ ## Batch and any payload
74
+
75
+ 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.
76
+
77
+ 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.
78
+
79
+ ```python
80
+ batch = laser.publish_batch("orders").inline_payload()
81
+ batch.extend_json([{"id": "o-1", "amount": 129}, {"id": "o-2", "amount": 80}])
82
+ batch.add_payload(b"\x00any-bytes-any-format") # raw bytes, untouched by the SDK
83
+ await batch.send() # the whole batch, one round-trip
84
+ ```
85
+
86
+ ## Schema-first bodies (Avro / Protobuf)
87
+
88
+ Compile a registered writer schema once, then publish raw datums under it. The
89
+ body is encoded client-side, so a value that stops matching the schema fails
90
+ before publishing rather than as a managed-side warning you cannot see. The
91
+ managed plane resolves the schema by id and extracts indexed columns from the
92
+ binary body.
93
+
94
+ ```python
95
+ from laser_sdk import CompiledSchema
96
+
97
+ source = {"kind": "avro", "schema": fill_avro_schema}
98
+ schema_id = await laser.register_schema(source, name="fill")
99
+ compiled = CompiledSchema.compile(source, id=schema_id)
100
+
101
+ batch = laser.publish_batch("trades_avro").inline_payload()
102
+ for fill in fills:
103
+ batch = batch.add_avro(compiled, schema_id, fill)
104
+ await batch.send()
105
+ ```
106
+
107
+ `CompiledSchema` also offers `validate` / `validate_value` / `decode`, and the
108
+ single-record builder has `.avro(compiled, schema_id, value)`. For Protobuf or
109
+ your own framing, encode the body yourself and ship it with
110
+ `.raw_bytes(bytes, "protobuf")` (or batch `.add_raw_bytes(..)`). Writer schemas
111
+ live on LaserData Cloud, so registration is a managed feature.
112
+
113
+ ## Query (managed)
114
+
115
+ ```python
116
+ rows = await (
117
+ laser.query("orders")
118
+ .where_eq("customer_id", "alice")
119
+ .filter_gte("total", 100)
120
+ .order_desc("total")
121
+ .limit(10)
122
+ .with_payload()
123
+ .fetch_all()
124
+ )
125
+ for row in rows:
126
+ print(row.headers, row.json())
127
+ ```
128
+
129
+ Query, the key-value store, and forks are managed features served by LaserData Cloud. Against raw Apache Iggy they raise `UnsupportedError`.
130
+
131
+ ## Key-value
132
+
133
+ ```python
134
+ kv = laser.kv("sessions")
135
+ await kv.set("user:42").json({"state": "online"}).ttl(300).send()
136
+ state = await kv.get_typed("user:42")
137
+ await kv.delete("user:42")
138
+ ```
139
+
140
+ ## Agents
141
+
142
+ ```python
143
+ from laser_sdk import Laser
144
+
145
+ async def handle(ctx, message):
146
+ text = message.payload.decode()
147
+ await ctx.respond(f"echo: {text}".encode())
148
+
149
+ laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
150
+ await laser.bootstrap(partitions=4)
151
+
152
+ handle_agent = laser.spawn_agent(
153
+ "echo", "agent.commands", handle, respond_on="agent.responses"
154
+ )
155
+ await handle_agent.ready()
156
+
157
+ from laser_sdk import Provenance
158
+ reply = await laser.request(
159
+ "agent.commands", "agent.responses", b"hello",
160
+ Provenance(agent="caller"), timeout_secs=10,
161
+ )
162
+ print(reply.payload.decode())
163
+
164
+ await handle_agent.shutdown()
165
+ ```
166
+
167
+ For a human-in-the-loop pause, the typed AGDX producer's `request_input` publishes
168
+ a prompt and blocks on the human's correlated reply, which a handler resolves with
169
+ `AgentCtx.respond_input`:
170
+
171
+ ```python
172
+ decision = await laser.agdx("agent.human_input", "orchestrator", conversation_id).request_input(
173
+ "agent.responses", b"approve a $500 refund?", timeout_secs=15
174
+ )
175
+ ```
176
+
177
+ ## Consume and replay
178
+
179
+ ```python
180
+ # A resumable reader over a topic. Each poll drains what is new. Persist the
181
+ # offsets to resume after a restart.
182
+ cursor = laser.reader("orders")
183
+ for message in await cursor.poll():
184
+ print(message.json())
185
+ saved = cursor.offsets
186
+
187
+ # Replay a conversation's history off the log (agent runtime).
188
+ history = await laser.assemble_context(conversation_id, last_n=50)
189
+ ```
190
+
191
+ ## Memory and state
192
+
193
+ 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.
194
+
195
+ ```python
196
+ async def embed(text: str) -> list[float]:
197
+ ... # your model, or a deterministic stand-in
198
+
199
+ memory = laser.vector_memory(embed)
200
+ await memory.remember("checkout latency traces to the database pool", conversation=cid)
201
+ hits = await memory.recall(conversation=cid, semantic="why is checkout slow", limit=3)
202
+ print([item.text for item in hits])
203
+
204
+ # A durable key/value seam for agent state, the same vocabulary as the managed store.
205
+ store = ls.InMemoryStore() # or ls.FileStore("/var/lib/agent")
206
+ await store.set("cursor", saved_bytes)
207
+ value = await store.get("cursor")
208
+ ```
209
+
210
+ ## Edge interop (A2A / MCP / AG-UI)
211
+
212
+ 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:
213
+
214
+ ```python
215
+ # A2A: submit a task, poll for the result.
216
+ a2a = laser.a2a_bridge("a2a-gateway", "agent.commands", "agent.responses")
217
+ task = await a2a.submit({"message": {"role": "user", "parts": [{"kind": "text", "text": "hi"}]}})
218
+ status = await a2a.task(task["id"])
219
+
220
+ # MCP: advertise tools, route tools/call to the agent.
221
+ mcp = laser.mcp_bridge(
222
+ "mcp-gateway", "agent.tool_calls", "agent.tool_results", "laser-mcp",
223
+ tools=[{"name": "ask", "input_schema": {"type": "object"}}],
224
+ )
225
+ tools = mcp.list_tools()
226
+ result = await mcp.call_tool("ask", {"q": "what is AGDX?"})
227
+
228
+ # An agent answers a bridge request from its handler:
229
+ async def handle(ctx, message):
230
+ await ctx.respond_input("agent.responses", b"the answer")
231
+
232
+ # AG-UI: snapshot + deltas reconstruct shared state off the log.
233
+ await laser.publish_state_snapshot("agent.llm_io", "ui", conversation_id, {"count": 1})
234
+ state = await laser.reconstruct_state(conversation_id, "agent.llm_io")
235
+ events = await laser.agui_events(conversation_id, "agent.llm_io")
236
+ ```
237
+
238
+ Host the actual HTTP endpoint with your Python web framework over these adapter methods.
239
+
240
+ ## Errors
241
+
242
+ 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.
243
+
244
+ ## License
245
+
246
+ Apache-2.0.
247
+
@@ -0,0 +1,221 @@
1
+ # laser-sdk (Python)
2
+
3
+ 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.
4
+
5
+ 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.
6
+
7
+ 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`.
8
+
9
+ ## Install
10
+
11
+ ```
12
+ pip install laser-sdk
13
+ ```
14
+
15
+ Wheels ship for Linux (x86_64, aarch64) and macOS (Intel, Apple Silicon), Python 3.10 through 3.13.
16
+
17
+ ## Connect
18
+
19
+ ```python
20
+ import asyncio
21
+ from laser_sdk import Laser
22
+
23
+ async def main():
24
+ laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
25
+ caps = await laser.capabilities()
26
+ print(caps)
27
+
28
+ asyncio.run(main())
29
+ ```
30
+
31
+ 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.
32
+
33
+ ## Publish and consume
34
+
35
+ ```python
36
+ await laser.ensure_topic("orders", partitions=4)
37
+
38
+ await (
39
+ laser.publish("orders")
40
+ .index("customer_id", "alice")
41
+ .index("total", "129")
42
+ .inline_payload()
43
+ .json({"id": "o-1", "customer": "alice", "amount": 129})
44
+ .send()
45
+ )
46
+ ```
47
+
48
+ ## Batch and any payload
49
+
50
+ 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.
51
+
52
+ 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.
53
+
54
+ ```python
55
+ batch = laser.publish_batch("orders").inline_payload()
56
+ batch.extend_json([{"id": "o-1", "amount": 129}, {"id": "o-2", "amount": 80}])
57
+ batch.add_payload(b"\x00any-bytes-any-format") # raw bytes, untouched by the SDK
58
+ await batch.send() # the whole batch, one round-trip
59
+ ```
60
+
61
+ ## Schema-first bodies (Avro / Protobuf)
62
+
63
+ Compile a registered writer schema once, then publish raw datums under it. The
64
+ body is encoded client-side, so a value that stops matching the schema fails
65
+ before publishing rather than as a managed-side warning you cannot see. The
66
+ managed plane resolves the schema by id and extracts indexed columns from the
67
+ binary body.
68
+
69
+ ```python
70
+ from laser_sdk import CompiledSchema
71
+
72
+ source = {"kind": "avro", "schema": fill_avro_schema}
73
+ schema_id = await laser.register_schema(source, name="fill")
74
+ compiled = CompiledSchema.compile(source, id=schema_id)
75
+
76
+ batch = laser.publish_batch("trades_avro").inline_payload()
77
+ for fill in fills:
78
+ batch = batch.add_avro(compiled, schema_id, fill)
79
+ await batch.send()
80
+ ```
81
+
82
+ `CompiledSchema` also offers `validate` / `validate_value` / `decode`, and the
83
+ single-record builder has `.avro(compiled, schema_id, value)`. For Protobuf or
84
+ your own framing, encode the body yourself and ship it with
85
+ `.raw_bytes(bytes, "protobuf")` (or batch `.add_raw_bytes(..)`). Writer schemas
86
+ live on LaserData Cloud, so registration is a managed feature.
87
+
88
+ ## Query (managed)
89
+
90
+ ```python
91
+ rows = await (
92
+ laser.query("orders")
93
+ .where_eq("customer_id", "alice")
94
+ .filter_gte("total", 100)
95
+ .order_desc("total")
96
+ .limit(10)
97
+ .with_payload()
98
+ .fetch_all()
99
+ )
100
+ for row in rows:
101
+ print(row.headers, row.json())
102
+ ```
103
+
104
+ Query, the key-value store, and forks are managed features served by LaserData Cloud. Against raw Apache Iggy they raise `UnsupportedError`.
105
+
106
+ ## Key-value
107
+
108
+ ```python
109
+ kv = laser.kv("sessions")
110
+ await kv.set("user:42").json({"state": "online"}).ttl(300).send()
111
+ state = await kv.get_typed("user:42")
112
+ await kv.delete("user:42")
113
+ ```
114
+
115
+ ## Agents
116
+
117
+ ```python
118
+ from laser_sdk import Laser
119
+
120
+ async def handle(ctx, message):
121
+ text = message.payload.decode()
122
+ await ctx.respond(f"echo: {text}".encode())
123
+
124
+ laser = await Laser.connect("iggy://iggy:iggy@127.0.0.1:8090", stream="agents")
125
+ await laser.bootstrap(partitions=4)
126
+
127
+ handle_agent = laser.spawn_agent(
128
+ "echo", "agent.commands", handle, respond_on="agent.responses"
129
+ )
130
+ await handle_agent.ready()
131
+
132
+ from laser_sdk import Provenance
133
+ reply = await laser.request(
134
+ "agent.commands", "agent.responses", b"hello",
135
+ Provenance(agent="caller"), timeout_secs=10,
136
+ )
137
+ print(reply.payload.decode())
138
+
139
+ await handle_agent.shutdown()
140
+ ```
141
+
142
+ For a human-in-the-loop pause, the typed AGDX producer's `request_input` publishes
143
+ a prompt and blocks on the human's correlated reply, which a handler resolves with
144
+ `AgentCtx.respond_input`:
145
+
146
+ ```python
147
+ decision = await laser.agdx("agent.human_input", "orchestrator", conversation_id).request_input(
148
+ "agent.responses", b"approve a $500 refund?", timeout_secs=15
149
+ )
150
+ ```
151
+
152
+ ## Consume and replay
153
+
154
+ ```python
155
+ # A resumable reader over a topic. Each poll drains what is new. Persist the
156
+ # offsets to resume after a restart.
157
+ cursor = laser.reader("orders")
158
+ for message in await cursor.poll():
159
+ print(message.json())
160
+ saved = cursor.offsets
161
+
162
+ # Replay a conversation's history off the log (agent runtime).
163
+ history = await laser.assemble_context(conversation_id, last_n=50)
164
+ ```
165
+
166
+ ## Memory and state
167
+
168
+ 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.
169
+
170
+ ```python
171
+ async def embed(text: str) -> list[float]:
172
+ ... # your model, or a deterministic stand-in
173
+
174
+ memory = laser.vector_memory(embed)
175
+ await memory.remember("checkout latency traces to the database pool", conversation=cid)
176
+ hits = await memory.recall(conversation=cid, semantic="why is checkout slow", limit=3)
177
+ print([item.text for item in hits])
178
+
179
+ # A durable key/value seam for agent state, the same vocabulary as the managed store.
180
+ store = ls.InMemoryStore() # or ls.FileStore("/var/lib/agent")
181
+ await store.set("cursor", saved_bytes)
182
+ value = await store.get("cursor")
183
+ ```
184
+
185
+ ## Edge interop (A2A / MCP / AG-UI)
186
+
187
+ 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:
188
+
189
+ ```python
190
+ # A2A: submit a task, poll for the result.
191
+ a2a = laser.a2a_bridge("a2a-gateway", "agent.commands", "agent.responses")
192
+ task = await a2a.submit({"message": {"role": "user", "parts": [{"kind": "text", "text": "hi"}]}})
193
+ status = await a2a.task(task["id"])
194
+
195
+ # MCP: advertise tools, route tools/call to the agent.
196
+ mcp = laser.mcp_bridge(
197
+ "mcp-gateway", "agent.tool_calls", "agent.tool_results", "laser-mcp",
198
+ tools=[{"name": "ask", "input_schema": {"type": "object"}}],
199
+ )
200
+ tools = mcp.list_tools()
201
+ result = await mcp.call_tool("ask", {"q": "what is AGDX?"})
202
+
203
+ # An agent answers a bridge request from its handler:
204
+ async def handle(ctx, message):
205
+ await ctx.respond_input("agent.responses", b"the answer")
206
+
207
+ # AG-UI: snapshot + deltas reconstruct shared state off the log.
208
+ await laser.publish_state_snapshot("agent.llm_io", "ui", conversation_id, {"count": 1})
209
+ state = await laser.reconstruct_state(conversation_id, "agent.llm_io")
210
+ events = await laser.agui_events(conversation_id, "agent.llm_io")
211
+ ```
212
+
213
+ Host the actual HTTP endpoint with your Python web framework over these adapter methods.
214
+
215
+ ## Errors
216
+
217
+ 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.
218
+
219
+ ## License
220
+
221
+ Apache-2.0.
@@ -0,0 +1,6 @@
1
+ /target
2
+ /dist
3
+ /.venv
4
+ *.so
5
+ __pycache__/
6
+ *.egg-info/