inputlayer-client-dev 0.1.0__tar.gz → 0.1.0.dev913__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 (143) hide show
  1. inputlayer_client_dev-0.1.0.dev913/.gitignore +1 -0
  2. inputlayer_client_dev-0.1.0/README.md → inputlayer_client_dev-0.1.0.dev913/PKG-INFO +234 -7
  3. inputlayer_client_dev-0.1.0/PKG-INFO → inputlayer_client_dev-0.1.0.dev913/README.md +201 -23
  4. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/01_quickstart.py +7 -1
  5. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/02_social_network.py +6 -1
  6. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/03_rag_pipeline.py +6 -1
  7. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/04_ecommerce.py +6 -1
  8. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/05_rbac.py +6 -1
  9. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/06_realtime_dashboard.py +7 -2
  10. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/07_dataframe_etl.py +6 -1
  11. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/08_session_rules.py +6 -1
  12. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/09_access_control.py +6 -1
  13. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/examples/10_migrations.py +0 -1
  14. inputlayer_client_dev-0.1.0.dev913/examples/langchain/__init__.py +1 -0
  15. inputlayer_client_dev-0.1.0.dev913/examples/langchain/_common.py +368 -0
  16. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex01_retriever.py +49 -0
  17. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex02_vector.py +49 -0
  18. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex03_tool.py +52 -0
  19. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex04_lcel_chain.py +60 -0
  20. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex05_kg_building.py +118 -0
  21. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex06_explainable_rag.py +196 -0
  22. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex07_multihop.py +200 -0
  23. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex08_memory.py +221 -0
  24. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex09_access_control.py +202 -0
  25. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex10_multi_agent.py +224 -0
  26. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex11_anomaly.py +195 -0
  27. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex12_hallucination.py +223 -0
  28. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex13_guardrails.py +207 -0
  29. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex14_graphrag.py +320 -0
  30. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex15_caching.py +150 -0
  31. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex16_recommendation.py +164 -0
  32. inputlayer_client_dev-0.1.0.dev913/examples/langchain/ex17_lineage.py +202 -0
  33. inputlayer_client_dev-0.1.0.dev913/examples/langchain/runner.py +179 -0
  34. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/__init__.py +1 -0
  35. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/_common.py +133 -0
  36. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex01_reasoning_loop.py +264 -0
  37. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex02_investigation.py +332 -0
  38. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex03_human_in_loop.py +292 -0
  39. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex04_branching_pipeline.py +367 -0
  40. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex05_self_correcting.py +328 -0
  41. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex06_collaborative_planning.py +354 -0
  42. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex07_event_correlation.py +326 -0
  43. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex08_tool_selection.py +386 -0
  44. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex09_streaming_aggregation.py +411 -0
  45. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex10_resumable_graph.py +189 -0
  46. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex11_memory.py +238 -0
  47. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/ex12_resumable_chat.py +157 -0
  48. inputlayer_client_dev-0.1.0.dev913/examples/langgraph/runner.py +146 -0
  49. inputlayer_client_dev-0.1.0.dev913/pyproject.toml +65 -0
  50. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/__init__.py +87 -75
  51. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/_ast.py +4 -5
  52. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/_naming.py +2 -2
  53. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/_protocol.py +12 -3
  54. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/_proxy.py +22 -3
  55. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/_sync.py +104 -0
  56. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/aggregations.py +10 -10
  57. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/auth.py +117 -0
  58. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/client.py +43 -8
  59. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/client_sync.py +260 -0
  60. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/compiler.py +125 -104
  61. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/connection.py +74 -13
  62. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/derived.py +2 -2
  63. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/exceptions.py +24 -2
  64. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/functions.py +2 -2
  65. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/index.py +2 -2
  66. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/__init__.py +8 -0
  67. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langchain/__init__.py +38 -0
  68. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langchain/params.py +130 -0
  69. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langchain/retriever.py +354 -0
  70. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langchain/tool.py +460 -0
  71. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langchain/vector_store.py +651 -0
  72. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/__init__.py +60 -0
  73. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/_checkpoint_serde.py +96 -0
  74. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/_checkpointer_mixin.py +357 -0
  75. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/_memory_helpers.py +181 -0
  76. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/_memory_mixin.py +139 -0
  77. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/_utils.py +145 -0
  78. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/checkpointer.py +506 -0
  79. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/memory.py +557 -0
  80. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/nodes.py +190 -0
  81. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/router.py +155 -0
  82. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/integrations/langgraph/state.py +40 -0
  83. inputlayer_client_dev-0.1.0.dev913/src/inputlayer/knowledge_graph.py +992 -0
  84. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/__init__.py +11 -11
  85. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/cli.py +14 -5
  86. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/executor.py +2 -4
  87. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/loader.py +0 -1
  88. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/operations.py +12 -12
  89. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/recorder.py +3 -3
  90. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/state.py +6 -6
  91. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/writer.py +32 -7
  92. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/notifications.py +16 -5
  93. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/relation.py +3 -3
  94. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/result.py +20 -6
  95. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/session.py +5 -7
  96. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/types.py +4 -4
  97. inputlayer_client_dev-0.1.0.dev913/tests/_mock_checkpoint_kg.py +281 -0
  98. inputlayer_client_dev-0.1.0.dev913/tests/_mock_memory_kg.py +156 -0
  99. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/conftest.py +1 -5
  100. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_aggregations.py +2 -2
  101. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_ast.py +2 -4
  102. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_autodetector.py +0 -2
  103. inputlayer_client_dev-0.1.0.dev913/tests/test_checkpointer_core.py +600 -0
  104. inputlayer_client_dev-0.1.0.dev913/tests/test_checkpointer_lifecycle.py +204 -0
  105. inputlayer_client_dev-0.1.0.dev913/tests/test_checkpointer_list.py +226 -0
  106. inputlayer_client_dev-0.1.0.dev913/tests/test_checkpointer_validation.py +271 -0
  107. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_cli.py +6 -5
  108. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_compiler.py +33 -15
  109. inputlayer_client_dev-0.1.0.dev913/tests/test_connection.py +652 -0
  110. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_derived.py +3 -3
  111. inputlayer_client_dev-0.1.0.dev913/tests/test_escape_iql.py +145 -0
  112. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_executor.py +3 -5
  113. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_functions.py +13 -5
  114. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_integration.py +9 -7
  115. inputlayer_client_dev-0.1.0.dev913/tests/test_kg_node.py +509 -0
  116. inputlayer_client_dev-0.1.0.dev913/tests/test_kg_router.py +437 -0
  117. inputlayer_client_dev-0.1.0.dev913/tests/test_langchain.py +1894 -0
  118. inputlayer_client_dev-0.1.0.dev913/tests/test_langgraph_integration.py +343 -0
  119. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_loader.py +7 -7
  120. inputlayer_client_dev-0.1.0.dev913/tests/test_memory_core.py +409 -0
  121. inputlayer_client_dev-0.1.0.dev913/tests/test_memory_edge_cases.py +538 -0
  122. inputlayer_client_dev-0.1.0.dev913/tests/test_memory_helpers.py +215 -0
  123. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_operations.py +10 -11
  124. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_protocol.py +1 -2
  125. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_proxy.py +3 -1
  126. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_relation.py +3 -2
  127. inputlayer_client_dev-0.1.0.dev913/tests/test_serde.py +135 -0
  128. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_state.py +1 -4
  129. inputlayer_client_dev-0.1.0.dev913/tests/test_sync.py +702 -0
  130. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_types.py +11 -12
  131. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_writer.py +4 -8
  132. inputlayer_client_dev-0.1.0.dev913/uv.lock +2074 -0
  133. inputlayer_client_dev-0.1.0/.gitignore +0 -71
  134. inputlayer_client_dev-0.1.0/pyproject.toml +0 -33
  135. inputlayer_client_dev-0.1.0/src/inputlayer/auth.py +0 -70
  136. inputlayer_client_dev-0.1.0/src/inputlayer/client_sync.py +0 -231
  137. inputlayer_client_dev-0.1.0/src/inputlayer/knowledge_graph.py +0 -589
  138. inputlayer_client_dev-0.1.0/tests/test_connection.py +0 -202
  139. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/migrations/autodetector.py +0 -0
  140. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/src/inputlayer/py.typed +0 -0
  141. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/__init__.py +0 -0
  142. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_naming.py +0 -0
  143. {inputlayer_client_dev-0.1.0 → inputlayer_client_dev-0.1.0.dev913}/tests/test_result.py +0 -0
@@ -0,0 +1 @@
1
+ .coverage
@@ -1,6 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: inputlayer-client-dev
3
+ Version: 0.1.0.dev913
4
+ Summary: Python Object-Logic Mapper for InputLayer knowledge graph engine
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: pydantic<3,>=2.0
8
+ Requires-Dist: websockets<15,>=12.0
9
+ Provides-Extra: all
10
+ Requires-Dist: langchain-core<2,>=0.3; extra == 'all'
11
+ Requires-Dist: langgraph<2,>=0.2; extra == 'all'
12
+ Requires-Dist: pandas>=1.5; extra == 'all'
13
+ Requires-Dist: typing-extensions>=4.0; (python_version < '3.11') and extra == 'all'
14
+ Provides-Extra: dev
15
+ Requires-Dist: langchain-core<2,>=0.3; extra == 'dev'
16
+ Requires-Dist: langchain-openai>=1.0; extra == 'dev'
17
+ Requires-Dist: langgraph<2,>=0.2; extra == 'dev'
18
+ Requires-Dist: mypy>=1.13; extra == 'dev'
19
+ Requires-Dist: pandas>=1.5; extra == 'dev'
20
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
21
+ Requires-Dist: pytest>=7.0; extra == 'dev'
22
+ Requires-Dist: ruff>=0.8; extra == 'dev'
23
+ Requires-Dist: typing-extensions>=4.0; (python_version < '3.11') and extra == 'dev'
24
+ Provides-Extra: langchain
25
+ Requires-Dist: langchain-core<2,>=0.3; extra == 'langchain'
26
+ Provides-Extra: langgraph
27
+ Requires-Dist: langchain-core<2,>=0.3; extra == 'langgraph'
28
+ Requires-Dist: langgraph<2,>=0.2; extra == 'langgraph'
29
+ Requires-Dist: typing-extensions>=4.0; (python_version < '3.11') and extra == 'langgraph'
30
+ Provides-Extra: pandas
31
+ Requires-Dist: pandas>=1.5; extra == 'pandas'
32
+ Description-Content-Type: text/markdown
33
+
1
34
  # inputlayer-client-dev
2
35
 
3
- Python Object-Logic Mapper (OLM) for [InputLayer](https://github.com/inputlayer/inputlayer) - the symbolic reasoning engine for AI agents.
36
+ Python Object-Logic Mapper (OLM) for [InputLayer](https://github.com/inputlayer/inputlayer) - the streaming reasoning layer for AI systems.
4
37
 
5
38
  Write Python. No query syntax required. The OLM compiles typed Python classes into InputLayer queries over WebSocket.
6
39
 
@@ -9,8 +42,10 @@ Write Python. No query syntax required. The OLM compiles typed Python classes in
9
42
  ```bash
10
43
  pip install inputlayer-client-dev
11
44
 
12
- # With pandas DataFrame support
13
- pip install inputlayer-client-dev[pandas]
45
+ # With extras
46
+ pip install inputlayer-client-dev[pandas] # DataFrame support
47
+ pip install inputlayer-client-dev[langchain] # LangChain integration
48
+ pip install inputlayer-client-dev[all] # everything
14
49
  ```
15
50
 
16
51
  Requirements: Python 3.10+ and a running InputLayer server.
@@ -180,6 +215,195 @@ def on_update(event):
180
215
  print(f"{event.count} new readings")
181
216
  ```
182
217
 
218
+ ## LangChain Integration
219
+
220
+ ```bash
221
+ pip install inputlayer-client-dev[langchain]
222
+ ```
223
+
224
+ The full integration guide lives at [docs/guides/langchain](../../docs/content/docs/guides/langchain.mdx). Highlights:
225
+
226
+ ### Vector store
227
+
228
+ Drop-in `langchain_core.vectorstores.VectorStore` backed by an InputLayer `Relation`. Embeds documents through any LangChain `Embeddings` instance, supports metadata filters, deletion, and `as_retriever()`:
229
+
230
+ ```python
231
+ from inputlayer import Relation, Vector
232
+ from inputlayer.integrations.langchain import InputLayerVectorStore
233
+ from langchain_openai import OpenAIEmbeddings
234
+
235
+ class Chunk(Relation):
236
+ id: str
237
+ content: str
238
+ source: str
239
+ embedding: Vector
240
+
241
+ await kg.define(Chunk)
242
+ vs = InputLayerVectorStore(kg=kg, relation=Chunk, embeddings=OpenAIEmbeddings())
243
+ await vs.aadd_texts(["..."], metadatas=[{"source": "wiki"}], ids=["doc1"])
244
+ docs = await vs.asimilarity_search("query", k=5, filter={"source": "wiki"})
245
+ ```
246
+
247
+ ### Retriever
248
+
249
+ `InputLayerRetriever` runs in vector mode (with an `Embeddings` instance) or in InputLayer Query Language mode with safe `:input` parameter binding:
250
+
251
+ ```python
252
+ from inputlayer.integrations.langchain import InputLayerRetriever
253
+
254
+ retriever = InputLayerRetriever(
255
+ kg=kg,
256
+ query="?article(I, T, C, Cat, E), user_interest(:input, Cat)",
257
+ page_content_columns=["content"],
258
+ metadata_columns=["title", "category"],
259
+ )
260
+ result = await retriever.ainvoke("alice")
261
+ ```
262
+
263
+ ### Structured agent tools
264
+
265
+ `tools_from_relations` generates one `StructuredTool` per `Relation` with typed equality, range, and IN-list filters. The LLM never has to write IQL:
266
+
267
+ ```python
268
+ from inputlayer.integrations.langchain import tools_from_relations
269
+ tools = tools_from_relations(kg, [Employee, Article])
270
+ agent = create_tool_calling_agent(llm, tools, prompt)
271
+ ```
272
+
273
+ For agents that genuinely need raw IQL access, `InputLayerIQLTool` is the escape hatch. All components support both sync (`invoke`) and async (`ainvoke`) and are safe to use inside Jupyter, FastAPI, and LangGraph.
274
+
275
+ ### Examples
276
+
277
+ See [`examples/langchain/`](examples/langchain/) — 17 examples covering AI/LLM integration patterns:
278
+
279
+ ```bash
280
+ # List all examples
281
+ uv run python -m examples.langchain.runner --list
282
+
283
+ # Run specific examples
284
+ uv run python -m examples.langchain.runner 1 3 9
285
+
286
+ # Run a range
287
+ uv run python -m examples.langchain.runner 1-5
288
+
289
+ # Run all
290
+ uv run python -m examples.langchain.runner --all
291
+ ```
292
+
293
+ | # | Example | Description |
294
+ |---|---------|-------------|
295
+ | 1 | Retriever + IQL | Join queries with `{input}` placeholder |
296
+ | 2 | Vector search | Cosine similarity with distance filter |
297
+ | 3 | Tool for agents | Raw IQL + template mode |
298
+ | 4 | LCEL chain | Full retriever \| prompt \| llm \| parser pipeline |
299
+ | 5 | KG building | Extract facts from documents with LLM |
300
+ | 6 | Explainable RAG | `.why()` proof trees + `.why_not()` explanations |
301
+ | 7 | Multi-hop reasoning | Transitive closure over org graph |
302
+ | 8 | Conversational memory | Chat turns as facts, rules derive context |
303
+ | 9 | Access-controlled RAG | Clearance-based document filtering via rules |
304
+ | 10 | Multi-agent | Researcher + fact-checker with shared KG |
305
+ | 11 | Anomaly detection | Salary band rules flag violations |
306
+ | 12 | Hallucination detection | Ground LLM claims against KG facts |
307
+ | 13 | Guardrails | Policy rules block unsafe content |
308
+ | 14 | GraphRAG | Entity extraction + community detection |
309
+ | 15 | Semantic caching | Cache LLM responses, topic-based matching |
310
+ | 16 | Recommendation engine | Collaborative filtering via IQL rules |
311
+ | 17 | Data lineage | Source attribution + conflict detection |
312
+
313
+ Requires a running InputLayer server and optionally LM Studio (or any OpenAI-compatible server) for LLM examples.
314
+
315
+ ## LangGraph Integration
316
+
317
+ Install the langgraph extra:
318
+
319
+ ```bash
320
+ pip install inputlayer-client-dev[langgraph]
321
+ ```
322
+
323
+ The LangGraph integration provides:
324
+
325
+ - **`InputLayerCheckpointer`**: Persist graph state in an InputLayer KG. Supports `prune_thread()` / `adelete_thread()` for storage management and full async/sync parity.
326
+ - **`InputLayerMemory`**: Semantic long-term memory. Stores conversation turns as facts, derives active topics and relevant context via rules. Supports `adelete_thread()` for thread cleanup.
327
+ - **`kg_node`**: Factory for query/insert/delete graph nodes.
328
+ - **`kg_router`**: Conditional edge routing driven by IQL queries.
329
+ - **`InputLayerState`**: TypedDict base class with the required `kg` field for graph state.
330
+ - **`escape_iql`**: String escaping for safe IQL interpolation in parameterized queries.
331
+
332
+ ```python
333
+ from inputlayer import InputLayer
334
+ from inputlayer.integrations.langgraph import (
335
+ InputLayerCheckpointer,
336
+ InputLayerMemory,
337
+ InputLayerState,
338
+ escape_iql,
339
+ kg_node,
340
+ kg_router,
341
+ )
342
+ from langgraph.graph import END, StateGraph
343
+
344
+ class MyState(InputLayerState):
345
+ question: str
346
+ answer: str
347
+
348
+ async with InputLayer("ws://localhost:8080/ws", username="admin", password="...") as il:
349
+ kg = il.knowledge_graph("my_agent")
350
+
351
+ # Checkpointer: persist graph state across process restarts
352
+ checkpointer = InputLayerCheckpointer(kg=kg)
353
+ await checkpointer.setup()
354
+
355
+ # Memory: semantic recall with rule-derived context
356
+ memory = InputLayerMemory(kg=kg)
357
+ await memory.setup()
358
+
359
+ # Build a graph with KG-driven nodes and routing
360
+ graph = StateGraph(MyState)
361
+ graph.add_node("search", kg_node(query="?relevant(X, Y)", state_key="results"))
362
+ graph.add_node("recall", memory.recall_node(state_key="context"))
363
+ graph.add_node("store", memory.store_node(state_key="new_message"))
364
+ graph.set_entry_point("recall")
365
+ graph.add_edge("recall", "search")
366
+ graph.add_edge("search", "store")
367
+ graph.add_edge("store", END)
368
+
369
+ app = graph.compile(checkpointer=checkpointer)
370
+ ```
371
+
372
+ ### LangGraph Examples
373
+
374
+ See [`examples/langgraph/`](examples/langgraph/) - 12 examples covering agent patterns:
375
+
376
+ ```bash
377
+ # List all examples
378
+ uv run python -m examples.langgraph.runner --list
379
+
380
+ # Run specific examples
381
+ uv run python -m examples.langgraph.runner 1 10 11
382
+
383
+ # Run a range
384
+ uv run python -m examples.langgraph.runner 1-5
385
+
386
+ # Run all
387
+ uv run python -m examples.langgraph.runner --all
388
+ ```
389
+
390
+ | # | Example | Description |
391
+ |---|---------|-------------|
392
+ | 1 | Reasoning loop | Accumulate facts, rules decide when to stop |
393
+ | 2 | Investigation | Multi-step evidence gathering |
394
+ | 3 | Human-in-the-loop | Policy rules gate actions for approval |
395
+ | 4 | Branching pipeline | Route documents through parallel analysis |
396
+ | 5 | Self-correcting agent | Validation rules catch and fix errors |
397
+ | 6 | Collaborative planning | Multi-agent task decomposition |
398
+ | 7 | Event correlation | Pattern detection across event streams |
399
+ | 8 | Tool selection | Rules pick the right tool per context |
400
+ | 9 | Streaming aggregation | Threshold-based alerts from streaming data |
401
+ | 10 | Resumable graph | Checkpoint, crash, resume from persisted state |
402
+ | 11 | Semantic memory | Store turns as facts, recall derived context |
403
+ | 12 | Resumable chat | Checkpointer and memory together on one KG |
404
+
405
+ Requires a running InputLayer server. Examples marked [LLM] need LM Studio (or any OpenAI-compatible server) at `localhost:1234`. Set `INPUTLAYER_URL`, `INPUTLAYER_USER`, `INPUTLAYER_PASSWORD` to override server defaults.
406
+
183
407
  ## Sync Client
184
408
 
185
409
  For scripts, notebooks, and non-async contexts:
@@ -260,7 +484,7 @@ The autodetector diffs your current Python models against the last migration's s
260
484
  | `revoke_access(username)` | Revoke per-KG access |
261
485
  | `list_acl()` | List access control entries |
262
486
  | `explain(*select, ...)` | Show query plan without executing |
263
- | `execute(datalog)` | Execute raw Datalog |
487
+ | `execute(iql)` | Execute raw IQL |
264
488
  | `status()` | Get server status |
265
489
  | `compact()` | Trigger storage compaction |
266
490
 
@@ -334,15 +558,18 @@ See the [`examples/`](examples/) directory:
334
558
  | `08_session_rules.py` | Ad-hoc ephemeral views |
335
559
  | `09_access_control.py` | User/ACL management |
336
560
  | `10_migrations.py` | Django-style schema versioning |
561
+ | `langchain/` | 17 LangChain integration examples (see above) |
337
562
 
338
563
  ## Development
339
564
 
340
565
  ```bash
341
566
  cd packages/inputlayer-py
342
- pip install -e ".[dev]"
343
- python -m pytest tests/ -v
567
+ uv sync --extra dev
568
+ uv run pytest tests/ -v
569
+ uv run ruff check src/ tests/
570
+ uv run mypy src/inputlayer/
344
571
  ```
345
572
 
346
573
  ## License
347
574
 
348
- AGPL-3.0
575
+ Apache 2.0 + Commons Clause. See [LICENSE](../../LICENSE).
@@ -1,22 +1,6 @@
1
- Metadata-Version: 2.4
2
- Name: inputlayer-client-dev
3
- Version: 0.1.0
4
- Summary: Python Object-Logic Mapper for InputLayer knowledge graph engine
5
- License-Expression: AGPL-3.0
6
- Requires-Python: >=3.10
7
- Requires-Dist: pydantic>=2.0
8
- Requires-Dist: websockets>=12.0
9
- Provides-Extra: dev
10
- Requires-Dist: pandas>=1.5; extra == 'dev'
11
- Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
12
- Requires-Dist: pytest>=7.0; extra == 'dev'
13
- Provides-Extra: pandas
14
- Requires-Dist: pandas>=1.5; extra == 'pandas'
15
- Description-Content-Type: text/markdown
16
-
17
1
  # inputlayer-client-dev
18
2
 
19
- Python Object-Logic Mapper (OLM) for [InputLayer](https://github.com/inputlayer/inputlayer) - the symbolic reasoning engine for AI agents.
3
+ Python Object-Logic Mapper (OLM) for [InputLayer](https://github.com/inputlayer/inputlayer) - the streaming reasoning layer for AI systems.
20
4
 
21
5
  Write Python. No query syntax required. The OLM compiles typed Python classes into InputLayer queries over WebSocket.
22
6
 
@@ -25,8 +9,10 @@ Write Python. No query syntax required. The OLM compiles typed Python classes in
25
9
  ```bash
26
10
  pip install inputlayer-client-dev
27
11
 
28
- # With pandas DataFrame support
29
- pip install inputlayer-client-dev[pandas]
12
+ # With extras
13
+ pip install inputlayer-client-dev[pandas] # DataFrame support
14
+ pip install inputlayer-client-dev[langchain] # LangChain integration
15
+ pip install inputlayer-client-dev[all] # everything
30
16
  ```
31
17
 
32
18
  Requirements: Python 3.10+ and a running InputLayer server.
@@ -196,6 +182,195 @@ def on_update(event):
196
182
  print(f"{event.count} new readings")
197
183
  ```
198
184
 
185
+ ## LangChain Integration
186
+
187
+ ```bash
188
+ pip install inputlayer-client-dev[langchain]
189
+ ```
190
+
191
+ The full integration guide lives at [docs/guides/langchain](../../docs/content/docs/guides/langchain.mdx). Highlights:
192
+
193
+ ### Vector store
194
+
195
+ Drop-in `langchain_core.vectorstores.VectorStore` backed by an InputLayer `Relation`. Embeds documents through any LangChain `Embeddings` instance, supports metadata filters, deletion, and `as_retriever()`:
196
+
197
+ ```python
198
+ from inputlayer import Relation, Vector
199
+ from inputlayer.integrations.langchain import InputLayerVectorStore
200
+ from langchain_openai import OpenAIEmbeddings
201
+
202
+ class Chunk(Relation):
203
+ id: str
204
+ content: str
205
+ source: str
206
+ embedding: Vector
207
+
208
+ await kg.define(Chunk)
209
+ vs = InputLayerVectorStore(kg=kg, relation=Chunk, embeddings=OpenAIEmbeddings())
210
+ await vs.aadd_texts(["..."], metadatas=[{"source": "wiki"}], ids=["doc1"])
211
+ docs = await vs.asimilarity_search("query", k=5, filter={"source": "wiki"})
212
+ ```
213
+
214
+ ### Retriever
215
+
216
+ `InputLayerRetriever` runs in vector mode (with an `Embeddings` instance) or in InputLayer Query Language mode with safe `:input` parameter binding:
217
+
218
+ ```python
219
+ from inputlayer.integrations.langchain import InputLayerRetriever
220
+
221
+ retriever = InputLayerRetriever(
222
+ kg=kg,
223
+ query="?article(I, T, C, Cat, E), user_interest(:input, Cat)",
224
+ page_content_columns=["content"],
225
+ metadata_columns=["title", "category"],
226
+ )
227
+ result = await retriever.ainvoke("alice")
228
+ ```
229
+
230
+ ### Structured agent tools
231
+
232
+ `tools_from_relations` generates one `StructuredTool` per `Relation` with typed equality, range, and IN-list filters. The LLM never has to write IQL:
233
+
234
+ ```python
235
+ from inputlayer.integrations.langchain import tools_from_relations
236
+ tools = tools_from_relations(kg, [Employee, Article])
237
+ agent = create_tool_calling_agent(llm, tools, prompt)
238
+ ```
239
+
240
+ For agents that genuinely need raw IQL access, `InputLayerIQLTool` is the escape hatch. All components support both sync (`invoke`) and async (`ainvoke`) and are safe to use inside Jupyter, FastAPI, and LangGraph.
241
+
242
+ ### Examples
243
+
244
+ See [`examples/langchain/`](examples/langchain/) — 17 examples covering AI/LLM integration patterns:
245
+
246
+ ```bash
247
+ # List all examples
248
+ uv run python -m examples.langchain.runner --list
249
+
250
+ # Run specific examples
251
+ uv run python -m examples.langchain.runner 1 3 9
252
+
253
+ # Run a range
254
+ uv run python -m examples.langchain.runner 1-5
255
+
256
+ # Run all
257
+ uv run python -m examples.langchain.runner --all
258
+ ```
259
+
260
+ | # | Example | Description |
261
+ |---|---------|-------------|
262
+ | 1 | Retriever + IQL | Join queries with `{input}` placeholder |
263
+ | 2 | Vector search | Cosine similarity with distance filter |
264
+ | 3 | Tool for agents | Raw IQL + template mode |
265
+ | 4 | LCEL chain | Full retriever \| prompt \| llm \| parser pipeline |
266
+ | 5 | KG building | Extract facts from documents with LLM |
267
+ | 6 | Explainable RAG | `.why()` proof trees + `.why_not()` explanations |
268
+ | 7 | Multi-hop reasoning | Transitive closure over org graph |
269
+ | 8 | Conversational memory | Chat turns as facts, rules derive context |
270
+ | 9 | Access-controlled RAG | Clearance-based document filtering via rules |
271
+ | 10 | Multi-agent | Researcher + fact-checker with shared KG |
272
+ | 11 | Anomaly detection | Salary band rules flag violations |
273
+ | 12 | Hallucination detection | Ground LLM claims against KG facts |
274
+ | 13 | Guardrails | Policy rules block unsafe content |
275
+ | 14 | GraphRAG | Entity extraction + community detection |
276
+ | 15 | Semantic caching | Cache LLM responses, topic-based matching |
277
+ | 16 | Recommendation engine | Collaborative filtering via IQL rules |
278
+ | 17 | Data lineage | Source attribution + conflict detection |
279
+
280
+ Requires a running InputLayer server and optionally LM Studio (or any OpenAI-compatible server) for LLM examples.
281
+
282
+ ## LangGraph Integration
283
+
284
+ Install the langgraph extra:
285
+
286
+ ```bash
287
+ pip install inputlayer-client-dev[langgraph]
288
+ ```
289
+
290
+ The LangGraph integration provides:
291
+
292
+ - **`InputLayerCheckpointer`**: Persist graph state in an InputLayer KG. Supports `prune_thread()` / `adelete_thread()` for storage management and full async/sync parity.
293
+ - **`InputLayerMemory`**: Semantic long-term memory. Stores conversation turns as facts, derives active topics and relevant context via rules. Supports `adelete_thread()` for thread cleanup.
294
+ - **`kg_node`**: Factory for query/insert/delete graph nodes.
295
+ - **`kg_router`**: Conditional edge routing driven by IQL queries.
296
+ - **`InputLayerState`**: TypedDict base class with the required `kg` field for graph state.
297
+ - **`escape_iql`**: String escaping for safe IQL interpolation in parameterized queries.
298
+
299
+ ```python
300
+ from inputlayer import InputLayer
301
+ from inputlayer.integrations.langgraph import (
302
+ InputLayerCheckpointer,
303
+ InputLayerMemory,
304
+ InputLayerState,
305
+ escape_iql,
306
+ kg_node,
307
+ kg_router,
308
+ )
309
+ from langgraph.graph import END, StateGraph
310
+
311
+ class MyState(InputLayerState):
312
+ question: str
313
+ answer: str
314
+
315
+ async with InputLayer("ws://localhost:8080/ws", username="admin", password="...") as il:
316
+ kg = il.knowledge_graph("my_agent")
317
+
318
+ # Checkpointer: persist graph state across process restarts
319
+ checkpointer = InputLayerCheckpointer(kg=kg)
320
+ await checkpointer.setup()
321
+
322
+ # Memory: semantic recall with rule-derived context
323
+ memory = InputLayerMemory(kg=kg)
324
+ await memory.setup()
325
+
326
+ # Build a graph with KG-driven nodes and routing
327
+ graph = StateGraph(MyState)
328
+ graph.add_node("search", kg_node(query="?relevant(X, Y)", state_key="results"))
329
+ graph.add_node("recall", memory.recall_node(state_key="context"))
330
+ graph.add_node("store", memory.store_node(state_key="new_message"))
331
+ graph.set_entry_point("recall")
332
+ graph.add_edge("recall", "search")
333
+ graph.add_edge("search", "store")
334
+ graph.add_edge("store", END)
335
+
336
+ app = graph.compile(checkpointer=checkpointer)
337
+ ```
338
+
339
+ ### LangGraph Examples
340
+
341
+ See [`examples/langgraph/`](examples/langgraph/) - 12 examples covering agent patterns:
342
+
343
+ ```bash
344
+ # List all examples
345
+ uv run python -m examples.langgraph.runner --list
346
+
347
+ # Run specific examples
348
+ uv run python -m examples.langgraph.runner 1 10 11
349
+
350
+ # Run a range
351
+ uv run python -m examples.langgraph.runner 1-5
352
+
353
+ # Run all
354
+ uv run python -m examples.langgraph.runner --all
355
+ ```
356
+
357
+ | # | Example | Description |
358
+ |---|---------|-------------|
359
+ | 1 | Reasoning loop | Accumulate facts, rules decide when to stop |
360
+ | 2 | Investigation | Multi-step evidence gathering |
361
+ | 3 | Human-in-the-loop | Policy rules gate actions for approval |
362
+ | 4 | Branching pipeline | Route documents through parallel analysis |
363
+ | 5 | Self-correcting agent | Validation rules catch and fix errors |
364
+ | 6 | Collaborative planning | Multi-agent task decomposition |
365
+ | 7 | Event correlation | Pattern detection across event streams |
366
+ | 8 | Tool selection | Rules pick the right tool per context |
367
+ | 9 | Streaming aggregation | Threshold-based alerts from streaming data |
368
+ | 10 | Resumable graph | Checkpoint, crash, resume from persisted state |
369
+ | 11 | Semantic memory | Store turns as facts, recall derived context |
370
+ | 12 | Resumable chat | Checkpointer and memory together on one KG |
371
+
372
+ Requires a running InputLayer server. Examples marked [LLM] need LM Studio (or any OpenAI-compatible server) at `localhost:1234`. Set `INPUTLAYER_URL`, `INPUTLAYER_USER`, `INPUTLAYER_PASSWORD` to override server defaults.
373
+
199
374
  ## Sync Client
200
375
 
201
376
  For scripts, notebooks, and non-async contexts:
@@ -276,7 +451,7 @@ The autodetector diffs your current Python models against the last migration's s
276
451
  | `revoke_access(username)` | Revoke per-KG access |
277
452
  | `list_acl()` | List access control entries |
278
453
  | `explain(*select, ...)` | Show query plan without executing |
279
- | `execute(datalog)` | Execute raw Datalog |
454
+ | `execute(iql)` | Execute raw IQL |
280
455
  | `status()` | Get server status |
281
456
  | `compact()` | Trigger storage compaction |
282
457
 
@@ -350,15 +525,18 @@ See the [`examples/`](examples/) directory:
350
525
  | `08_session_rules.py` | Ad-hoc ephemeral views |
351
526
  | `09_access_control.py` | User/ACL management |
352
527
  | `10_migrations.py` | Django-style schema versioning |
528
+ | `langchain/` | 17 LangChain integration examples (see above) |
353
529
 
354
530
  ## Development
355
531
 
356
532
  ```bash
357
533
  cd packages/inputlayer-py
358
- pip install -e ".[dev]"
359
- python -m pytest tests/ -v
534
+ uv sync --extra dev
535
+ uv run pytest tests/ -v
536
+ uv run ruff check src/ tests/
537
+ uv run mypy src/inputlayer/
360
538
  ```
361
539
 
362
540
  ## License
363
541
 
364
- AGPL-3.0
542
+ Apache 2.0 + Commons Clause. See [LICENSE](../../LICENSE).
@@ -1,6 +1,8 @@
1
1
  """Quickstart: connect, define, insert, query."""
2
2
 
3
3
  import asyncio
4
+ import os
5
+
4
6
  from inputlayer import InputLayer, Relation
5
7
 
6
8
 
@@ -13,7 +15,11 @@ class Employee(Relation):
13
15
 
14
16
 
15
17
  async def main():
16
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
18
+ async with InputLayer(
19
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
20
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
21
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
22
+ ) as il:
17
23
  kg = il.knowledge_graph("quickstart")
18
24
 
19
25
  # Define schema
@@ -1,6 +1,7 @@
1
1
  """Social network: graph traversal, transitive closure, mutual follows."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
  from typing import ClassVar
5
6
 
6
7
  from inputlayer import Derived, From, InputLayer, Relation
@@ -29,7 +30,11 @@ Reachable.rules = [
29
30
 
30
31
 
31
32
  async def main():
32
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
33
+ async with InputLayer(
34
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
35
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
36
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
37
+ ) as il:
33
38
  kg = il.knowledge_graph("social")
34
39
 
35
40
  await kg.define(Follow)
@@ -1,6 +1,7 @@
1
1
  """RAG pipeline: vector + structured hybrid search."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
 
5
6
  from inputlayer import HnswIndex, InputLayer, Relation, Vector
6
7
 
@@ -13,7 +14,11 @@ class Document(Relation):
13
14
 
14
15
 
15
16
  async def main():
16
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
17
+ async with InputLayer(
18
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
19
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
20
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
21
+ ) as il:
17
22
  kg = il.knowledge_graph("rag")
18
23
 
19
24
  await kg.define(Document)
@@ -1,6 +1,7 @@
1
1
  """E-commerce: collaborative filtering, revenue aggregation."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
 
5
6
  from inputlayer import InputLayer, Relation, count, sum_
6
7
 
@@ -12,7 +13,11 @@ class Purchase(Relation):
12
13
 
13
14
 
14
15
  async def main():
15
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
16
+ async with InputLayer(
17
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
18
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
19
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
20
+ ) as il:
16
21
  kg = il.knowledge_graph("ecommerce")
17
22
 
18
23
  await kg.define(Purchase)
@@ -1,6 +1,7 @@
1
1
  """RBAC: transitive role inheritance."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
  from typing import ClassVar
5
6
 
6
7
  from inputlayer import Derived, From, InputLayer, Relation
@@ -34,7 +35,11 @@ EffectiveRole.rules = [
34
35
 
35
36
 
36
37
  async def main():
37
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
38
+ async with InputLayer(
39
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
40
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
41
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
42
+ ) as il:
38
43
  kg = il.knowledge_graph("rbac")
39
44
 
40
45
  await kg.define(RoleHierarchy, UserRole)
@@ -1,8 +1,9 @@
1
1
  """Realtime dashboard: notifications + aggregation."""
2
2
 
3
3
  import asyncio
4
+ import os
4
5
 
5
- from inputlayer import InputLayer, Relation, count, sum_
6
+ from inputlayer import InputLayer, Relation, count
6
7
 
7
8
 
8
9
  class SensorReading(Relation):
@@ -12,7 +13,11 @@ class SensorReading(Relation):
12
13
 
13
14
 
14
15
  async def main():
15
- async with InputLayer("ws://localhost:8080/ws", username="admin", password="admin") as il:
16
+ async with InputLayer(
17
+ os.environ.get("INPUTLAYER_URL", "ws://localhost:8080/ws"),
18
+ username=os.environ.get("INPUTLAYER_USER", "admin"),
19
+ password=os.environ.get("INPUTLAYER_PASSWORD", "admin"),
20
+ ) as il:
16
21
  kg = il.knowledge_graph("dashboard")
17
22
 
18
23
  # Register notification handler