querygraph 0.2.0__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 (33) hide show
  1. querygraph-0.2.0/.gitignore +4 -0
  2. querygraph-0.2.0/PKG-INFO +172 -0
  3. querygraph-0.2.0/README.md +142 -0
  4. querygraph-0.2.0/RELEASES.md +12 -0
  5. querygraph-0.2.0/examples/README.md +51 -0
  6. querygraph-0.2.0/examples/osi_semantic_croissant.py +58 -0
  7. querygraph-0.2.0/examples/pyspark_query_sail.py +26 -0
  8. querygraph-0.2.0/examples/typedid_langchain_agents.py +33 -0
  9. querygraph-0.2.0/pyproject.toml +45 -0
  10. querygraph-0.2.0/querygraph/__init__.py +14 -0
  11. querygraph-0.2.0/querygraph/__main__.py +4 -0
  12. querygraph-0.2.0/querygraph/agents.py +89 -0
  13. querygraph-0.2.0/querygraph/base58.py +15 -0
  14. querygraph-0.2.0/querygraph/cdif.py +205 -0
  15. querygraph-0.2.0/querygraph/cli.py +123 -0
  16. querygraph-0.2.0/querygraph/codata.py +38 -0
  17. querygraph-0.2.0/querygraph/croissant.py +86 -0
  18. querygraph-0.2.0/querygraph/dataverse.py +155 -0
  19. querygraph-0.2.0/querygraph/did.py +51 -0
  20. querygraph-0.2.0/querygraph/lakehouse.py +115 -0
  21. querygraph-0.2.0/querygraph/lineage.py +106 -0
  22. querygraph-0.2.0/querygraph/navigator.py +141 -0
  23. querygraph-0.2.0/querygraph/odrl.py +60 -0
  24. querygraph-0.2.0/querygraph/odrl_rights.py +50 -0
  25. querygraph-0.2.0/querygraph/osi.py +155 -0
  26. querygraph-0.2.0/querygraph/qglake.py +99 -0
  27. querygraph-0.2.0/querygraph/rbac.py +31 -0
  28. querygraph-0.2.0/querygraph/typedid.py +211 -0
  29. querygraph-0.2.0/querygraph/validation.py +41 -0
  30. querygraph-0.2.0/tests/test_python_ecosystem.py +244 -0
  31. querygraph-0.2.0/tests/test_python_semantics.py +47 -0
  32. querygraph-0.2.0/tests/test_rust_equivalence.py +39 -0
  33. querygraph-0.2.0/uv.lock +1376 -0
@@ -0,0 +1,4 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
@@ -0,0 +1,172 @@
1
+ Metadata-Version: 2.4
2
+ Name: querygraph
3
+ Version: 0.2.0
4
+ Summary: Python port of the QueryGraph AI Navigator semantic layer
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: pydantic>=2.7
8
+ Provides-Extra: agents
9
+ Requires-Dist: langchain-core>=0.3; extra == 'agents'
10
+ Provides-Extra: all
11
+ Requires-Dist: googleapis-common-protos>=1.75.0; extra == 'all'
12
+ Requires-Dist: grpcio-status>=1.81.0; extra == 'all'
13
+ Requires-Dist: grpcio>=1.81.0; extra == 'all'
14
+ Requires-Dist: langchain-core>=0.3; extra == 'all'
15
+ Requires-Dist: pandas>=3.0.0; extra == 'all'
16
+ Requires-Dist: pyarrow>=24.0.0; extra == 'all'
17
+ Requires-Dist: pyspark>=4.1.2; extra == 'all'
18
+ Requires-Dist: zstandard>=0.25.0; extra == 'all'
19
+ Provides-Extra: lakehouse
20
+ Requires-Dist: googleapis-common-protos>=1.75.0; extra == 'lakehouse'
21
+ Requires-Dist: grpcio-status>=1.81.0; extra == 'lakehouse'
22
+ Requires-Dist: grpcio>=1.81.0; extra == 'lakehouse'
23
+ Requires-Dist: pandas>=3.0.0; extra == 'lakehouse'
24
+ Requires-Dist: pyarrow>=24.0.0; extra == 'lakehouse'
25
+ Requires-Dist: pyspark>=4.1.2; extra == 'lakehouse'
26
+ Requires-Dist: zstandard>=0.25.0; extra == 'lakehouse'
27
+ Provides-Extra: test
28
+ Requires-Dist: pytest>=8.0; extra == 'test'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # QueryGraph Python
32
+
33
+ Python ecosystem for the QueryGraph AI Navigator.
34
+
35
+ It mirrors and extends the Rust implementation in `../qg-rust`:
36
+
37
+ - Croissant JSON-LD dataset metadata
38
+ - CDIF discovery/access/profile projection
39
+ - deterministic `did:oyd` identity documents
40
+ - ODRL permissions and prohibitions
41
+ - OSI semantic models over Croissant fields and Sail columns
42
+ - TypeDID agents modeled with Pydantic
43
+ - optional LangChain adapters for governed agent tools
44
+ - OpenLineage events and DID-style attestations
45
+ - PySpark helpers for querying a local Sail warehouse
46
+ - a CLI compatible with the Rust semantic bundle commands
47
+
48
+ The design goal is Python-native ergonomics over the same governed lakehouse:
49
+ Rust loads and verifies the warehouse; Python gives notebooks, PySpark users,
50
+ LangChain agents, and data scientists a typed interop layer.
51
+
52
+ ## Stack versions
53
+
54
+ This port tracks the same coordinated QueryGraph stack releases as `../qg-rust`:
55
+
56
+ - **Grust 0.11.0 "Crab"** — the property-graph + GQL/Cypher substrate.
57
+ - **TypeSec 0.11.0 "Burano"** — the typed security fabric; the Pydantic
58
+ `TypeDidEnvelope` mirrors its audit-safe attestation (action, resource,
59
+ privacy level, negotiated profile, and an envelope digest).
60
+ - **LakeCat 0.2.1 "Lynx"** — the thin Iceberg REST catalog boundary, now sharing
61
+ its bootstrap-bundle wire format with the importer via `qglake-bundle`.
62
+
63
+ See `../qg-rust/docs/blog/announcing-querygraph-stack.md` for the full story.
64
+
65
+ ## Install
66
+
67
+ Core metadata and TypeDID/Pydantic support:
68
+
69
+ ```bash
70
+ uv sync
71
+ ```
72
+
73
+ Optional PySpark/Sail support:
74
+
75
+ ```bash
76
+ uv sync --extra lakehouse
77
+ ```
78
+
79
+ Optional LangChain tool adapters:
80
+
81
+ ```bash
82
+ uv sync --extra agents
83
+ ```
84
+
85
+ Everything:
86
+
87
+ ```bash
88
+ uv sync --extra all
89
+ ```
90
+
91
+ ## Build a Semantic Bundle
92
+
93
+ ```bash
94
+ python -m querygraph navigator \
95
+ --dataset-name "Hazard vocabulary" \
96
+ --description "Controlled vocabulary with multilingual technical terms" \
97
+ --landing-page "https://querygraph.ai/datasets/hazards" \
98
+ --data-url "https://querygraph.ai/datasets/hazards.csv"
99
+ ```
100
+
101
+ ## QG Lakehouse Agent Story
102
+
103
+ ```bash
104
+ python -m querygraph qglake-story --pretty
105
+ ```
106
+
107
+ This produces a Pydantic TypeDID multi-agent run: supervisor, finance, energy,
108
+ mobility, climate-health, reference, restricted-data broker, synthesis,
109
+ OpenLineage, and DID attestation.
110
+
111
+ ## Query Sail with PySpark
112
+
113
+ Start Sail from the Rust project after the lakehouse has been loaded:
114
+
115
+ ```bash
116
+ cd ../qg-rust
117
+ sail spark server --port 50051
118
+ ```
119
+
120
+ In another shell:
121
+
122
+ ```bash
123
+ cd ../qg-python
124
+ uv sync --extra lakehouse
125
+ uv run querygraph lakehouse-register \
126
+ --manifest ../qg-rust/.querygraph/lakehouse/manifest/load-report.json \
127
+ --warehouse ../qg-rust/spark-warehouse
128
+ uv run querygraph audit-register --warehouse ../qg-rust/spark-warehouse
129
+ uv run querygraph pyspark-examples
130
+ ```
131
+
132
+ Open a shell:
133
+
134
+ ```bash
135
+ uv run pyspark --remote sc://127.0.0.1:50051
136
+ ```
137
+
138
+ Then query the registered views:
139
+
140
+ ```python
141
+ spark.sql("SELECT COUNT(*) FROM global_temp.government_finance__countydata").show()
142
+ spark.sql("SELECT quantity, value, unit FROM global_temp.codata_constants_2022__codata_constants_2022 LIMIT 5").show(truncate=False)
143
+ spark.sql("SELECT event_hash, event_type, job_name FROM global_temp.openlineage_events LIMIT 10").show(truncate=False)
144
+ ```
145
+
146
+ ## OSI with Semantic Croissant
147
+
148
+ ```bash
149
+ uv run python examples/osi_semantic_croissant.py
150
+ ```
151
+
152
+ The example starts with concrete Semantic Croissant fields and projects them
153
+ into an OSI semantic model with ontology terms and Sail SQL expressions.
154
+
155
+ ## TypeDID Agents with LangChain
156
+
157
+ ```bash
158
+ uv sync --extra agents
159
+ uv run python examples/typedid_langchain_agents.py
160
+ ```
161
+
162
+ The agents are Pydantic models first. When LangChain is installed, a
163
+ `TypeDidLangChainToolAdapter` exposes the same governed agent as a LangChain
164
+ `StructuredTool`.
165
+
166
+ ## Test
167
+
168
+ ```bash
169
+ uv run python -m pytest
170
+ ```
171
+
172
+ The test suite includes equivalence checks against the sibling Rust implementation.
@@ -0,0 +1,142 @@
1
+ # QueryGraph Python
2
+
3
+ Python ecosystem for the QueryGraph AI Navigator.
4
+
5
+ It mirrors and extends the Rust implementation in `../qg-rust`:
6
+
7
+ - Croissant JSON-LD dataset metadata
8
+ - CDIF discovery/access/profile projection
9
+ - deterministic `did:oyd` identity documents
10
+ - ODRL permissions and prohibitions
11
+ - OSI semantic models over Croissant fields and Sail columns
12
+ - TypeDID agents modeled with Pydantic
13
+ - optional LangChain adapters for governed agent tools
14
+ - OpenLineage events and DID-style attestations
15
+ - PySpark helpers for querying a local Sail warehouse
16
+ - a CLI compatible with the Rust semantic bundle commands
17
+
18
+ The design goal is Python-native ergonomics over the same governed lakehouse:
19
+ Rust loads and verifies the warehouse; Python gives notebooks, PySpark users,
20
+ LangChain agents, and data scientists a typed interop layer.
21
+
22
+ ## Stack versions
23
+
24
+ This port tracks the same coordinated QueryGraph stack releases as `../qg-rust`:
25
+
26
+ - **Grust 0.11.0 "Crab"** — the property-graph + GQL/Cypher substrate.
27
+ - **TypeSec 0.11.0 "Burano"** — the typed security fabric; the Pydantic
28
+ `TypeDidEnvelope` mirrors its audit-safe attestation (action, resource,
29
+ privacy level, negotiated profile, and an envelope digest).
30
+ - **LakeCat 0.2.1 "Lynx"** — the thin Iceberg REST catalog boundary, now sharing
31
+ its bootstrap-bundle wire format with the importer via `qglake-bundle`.
32
+
33
+ See `../qg-rust/docs/blog/announcing-querygraph-stack.md` for the full story.
34
+
35
+ ## Install
36
+
37
+ Core metadata and TypeDID/Pydantic support:
38
+
39
+ ```bash
40
+ uv sync
41
+ ```
42
+
43
+ Optional PySpark/Sail support:
44
+
45
+ ```bash
46
+ uv sync --extra lakehouse
47
+ ```
48
+
49
+ Optional LangChain tool adapters:
50
+
51
+ ```bash
52
+ uv sync --extra agents
53
+ ```
54
+
55
+ Everything:
56
+
57
+ ```bash
58
+ uv sync --extra all
59
+ ```
60
+
61
+ ## Build a Semantic Bundle
62
+
63
+ ```bash
64
+ python -m querygraph navigator \
65
+ --dataset-name "Hazard vocabulary" \
66
+ --description "Controlled vocabulary with multilingual technical terms" \
67
+ --landing-page "https://querygraph.ai/datasets/hazards" \
68
+ --data-url "https://querygraph.ai/datasets/hazards.csv"
69
+ ```
70
+
71
+ ## QG Lakehouse Agent Story
72
+
73
+ ```bash
74
+ python -m querygraph qglake-story --pretty
75
+ ```
76
+
77
+ This produces a Pydantic TypeDID multi-agent run: supervisor, finance, energy,
78
+ mobility, climate-health, reference, restricted-data broker, synthesis,
79
+ OpenLineage, and DID attestation.
80
+
81
+ ## Query Sail with PySpark
82
+
83
+ Start Sail from the Rust project after the lakehouse has been loaded:
84
+
85
+ ```bash
86
+ cd ../qg-rust
87
+ sail spark server --port 50051
88
+ ```
89
+
90
+ In another shell:
91
+
92
+ ```bash
93
+ cd ../qg-python
94
+ uv sync --extra lakehouse
95
+ uv run querygraph lakehouse-register \
96
+ --manifest ../qg-rust/.querygraph/lakehouse/manifest/load-report.json \
97
+ --warehouse ../qg-rust/spark-warehouse
98
+ uv run querygraph audit-register --warehouse ../qg-rust/spark-warehouse
99
+ uv run querygraph pyspark-examples
100
+ ```
101
+
102
+ Open a shell:
103
+
104
+ ```bash
105
+ uv run pyspark --remote sc://127.0.0.1:50051
106
+ ```
107
+
108
+ Then query the registered views:
109
+
110
+ ```python
111
+ spark.sql("SELECT COUNT(*) FROM global_temp.government_finance__countydata").show()
112
+ spark.sql("SELECT quantity, value, unit FROM global_temp.codata_constants_2022__codata_constants_2022 LIMIT 5").show(truncate=False)
113
+ spark.sql("SELECT event_hash, event_type, job_name FROM global_temp.openlineage_events LIMIT 10").show(truncate=False)
114
+ ```
115
+
116
+ ## OSI with Semantic Croissant
117
+
118
+ ```bash
119
+ uv run python examples/osi_semantic_croissant.py
120
+ ```
121
+
122
+ The example starts with concrete Semantic Croissant fields and projects them
123
+ into an OSI semantic model with ontology terms and Sail SQL expressions.
124
+
125
+ ## TypeDID Agents with LangChain
126
+
127
+ ```bash
128
+ uv sync --extra agents
129
+ uv run python examples/typedid_langchain_agents.py
130
+ ```
131
+
132
+ The agents are Pydantic models first. When LangChain is installed, a
133
+ `TypeDidLangChainToolAdapter` exposes the same governed agent as a LangChain
134
+ `StructuredTool`.
135
+
136
+ ## Test
137
+
138
+ ```bash
139
+ uv run python -m pytest
140
+ ```
141
+
142
+ The test suite includes equivalence checks against the sibling Rust implementation.
@@ -0,0 +1,12 @@
1
+ # QueryGraph Python releases
2
+
3
+ The Python port shares the version line and codenames of the Rust
4
+ implementation. The canonical release scheme and codename pool (birds of prey)
5
+ live in `../qg-rust/RELEASES.md`.
6
+
7
+ ## Release log
8
+
9
+ | Version | Codename | Notes |
10
+ |---|---|---|
11
+ | 0.2.0 | Peregrine | Tracks Grust 0.11.0 "Crab", TypeSec 0.11.0 "Burano", LakeCat 0.2.1 "Lynx". TypeDID attestation parity (privacy / profile / envelope digest) with the Rust port. |
12
+ | 0.1.0 | — | (pre-codename) Initial Python port. |
@@ -0,0 +1,51 @@
1
+ # QueryGraph Python Examples
2
+
3
+ These examples turn the Python package into the notebook-facing ecosystem for
4
+ the Rust lakehouse.
5
+
6
+ ## Sail and PySpark
7
+
8
+ ```bash
9
+ sail spark server --port 50051
10
+ querygraph lakehouse-register \
11
+ --manifest ../qg-rust/.querygraph/lakehouse/manifest/load-report.json \
12
+ --warehouse ../qg-rust/spark-warehouse
13
+ querygraph audit-register --warehouse ../qg-rust/spark-warehouse
14
+ python examples/pyspark_query_sail.py
15
+ ```
16
+
17
+ Useful shell entry:
18
+
19
+ ```bash
20
+ pyspark --remote sc://127.0.0.1:50051
21
+ ```
22
+
23
+ Then:
24
+
25
+ ```python
26
+ spark.sql("SELECT COUNT(*) FROM global_temp.government_finance__countydata").show()
27
+ spark.sql("SELECT quantity, value, unit FROM global_temp.codata_constants_2022__codata_constants_2022 LIMIT 5").show(truncate=False)
28
+ spark.sql("SELECT event_hash, event_type, job_name FROM global_temp.openlineage_events LIMIT 10").show(truncate=False)
29
+ ```
30
+
31
+ ## OSI and Semantic Croissant
32
+
33
+ ```bash
34
+ python examples/osi_semantic_croissant.py
35
+ ```
36
+
37
+ The example starts with concrete Semantic Croissant fields and projects them
38
+ into an OSI model with business terms, Sail expressions, and ontology terms.
39
+
40
+ ## TypeDID, Pydantic, and LangChain
41
+
42
+ ```bash
43
+ python examples/typedid_langchain_agents.py
44
+ ```
45
+
46
+ For the LangChain adapter path:
47
+
48
+ ```bash
49
+ uv sync --extra agents
50
+ python examples/typedid_langchain_agents.py
51
+ ```
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ """Build OSI business semantics from a Semantic Croissant dataset."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+
7
+ from querygraph.croissant import CroissantDataset, Field, FileObject, RecordSet
8
+ from querygraph.osi import OsiDocument
9
+
10
+
11
+ dataset = CroissantDataset(
12
+ id="https://querygraph.ai/datasets/energy-burden/#dataset",
13
+ name="Energy Burden Demonstration",
14
+ description="Governed household energy survey fields in Sail.",
15
+ license="https://creativecommons.org/licenses/by/4.0/",
16
+ creators=["QueryGraph"],
17
+ files=[
18
+ FileObject(
19
+ id="https://querygraph.ai/datasets/energy-burden/#file",
20
+ name="energy_burden.parquet",
21
+ content_url="sail://qg_lakehouse/access_2018__access_data",
22
+ encoding_format="application/vnd.apache.parquet",
23
+ )
24
+ ],
25
+ record_sets=[
26
+ RecordSet(
27
+ id="https://querygraph.ai/datasets/energy-burden/#recordset",
28
+ name="energy burden observations",
29
+ fields=[
30
+ Field(
31
+ "household_id",
32
+ "sc:Text",
33
+ "Stable household identifier.",
34
+ ).semantic_type("https://schema.org/identifier"),
35
+ Field(
36
+ "energy_source",
37
+ "sc:Text",
38
+ "Primary household energy source.",
39
+ ).semantic_type("https://querygraph.ai/ontology/energySource"),
40
+ Field(
41
+ "monthly_energy_cost",
42
+ "sc:Float",
43
+ "Monthly energy cost in local currency.",
44
+ ).semantic_type("https://querygraph.ai/ontology/monthlyEnergyCost"),
45
+ ],
46
+ )
47
+ ],
48
+ keywords=["Semantic Croissant", "OSI", "energy burden", "Sail"],
49
+ )
50
+
51
+
52
+ def main() -> None:
53
+ osi = OsiDocument.from_croissant(dataset, sail_schema="qg_lakehouse")
54
+ print(json.dumps({"croissant": dataset.to_json_ld(), "osi": osi.to_json()}, indent=2))
55
+
56
+
57
+ if __name__ == "__main__":
58
+ main()
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env python3
2
+ """Query the locally registered QueryGraph Sail warehouse with PySpark.
3
+
4
+ Start Sail first:
5
+
6
+ sail spark server --port 50051
7
+
8
+ Then register tables:
9
+
10
+ querygraph lakehouse-register --warehouse ../qg-rust/spark-warehouse \
11
+ --manifest ../qg-rust/.querygraph/lakehouse/manifest/load-report.json
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from querygraph.lakehouse import example_queries, spark_session
16
+
17
+
18
+ def main() -> None:
19
+ spark = spark_session("sc://127.0.0.1:50051")
20
+ for sql in example_queries("global_temp"):
21
+ print(f"\n-- {sql}")
22
+ spark.sql(sql).show(truncate=False)
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env python3
2
+ """TypeDID agents with Pydantic models and an optional LangChain adapter."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+
7
+ from querygraph.agents import TypeDidLangChainToolAdapter, deterministic_specialist
8
+ from querygraph.qglake import build_python_qglake_story
9
+ from querygraph.typedid import TypeDidAgent
10
+
11
+
12
+ def main() -> None:
13
+ story = build_python_qglake_story()
14
+ print(json.dumps(story["synthesis"], indent=2))
15
+
16
+ finance = TypeDidAgent.new("FinanceAgent")
17
+ handler = deterministic_specialist(
18
+ finance,
19
+ summary="Fiscal capacity summary from governed Sail finance tables.",
20
+ evidence=["global_temp.government_finance__countydata"],
21
+ )
22
+
23
+ try:
24
+ tool = TypeDidLangChainToolAdapter(finance, handler).as_tool()
25
+ except RuntimeError as exc:
26
+ print(f"LangChain optional extra not installed: {exc}")
27
+ return
28
+
29
+ print(tool.invoke({"question": "Summarize fiscal capacity", "resource": "compartment:finance"}))
30
+
31
+
32
+ if __name__ == "__main__":
33
+ main()
@@ -0,0 +1,45 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "querygraph"
7
+ version = "0.2.0"
8
+ description = "Python port of the QueryGraph AI Navigator semantic layer"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ dependencies = [
13
+ "pydantic>=2.7",
14
+ ]
15
+
16
+ [project.optional-dependencies]
17
+ agents = [
18
+ "langchain-core>=0.3",
19
+ ]
20
+ lakehouse = [
21
+ "googleapis-common-protos>=1.75.0",
22
+ "grpcio>=1.81.0",
23
+ "grpcio-status>=1.81.0",
24
+ "pandas>=3.0.0",
25
+ "pyarrow>=24.0.0",
26
+ "pyspark>=4.1.2",
27
+ "zstandard>=0.25.0",
28
+ ]
29
+ test = ["pytest>=8.0"]
30
+ all = [
31
+ "googleapis-common-protos>=1.75.0",
32
+ "grpcio>=1.81.0",
33
+ "grpcio-status>=1.81.0",
34
+ "langchain-core>=0.3",
35
+ "pandas>=3.0.0",
36
+ "pyarrow>=24.0.0",
37
+ "pyspark>=4.1.2",
38
+ "zstandard>=0.25.0",
39
+ ]
40
+
41
+ [project.scripts]
42
+ querygraph = "querygraph.cli:main"
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
@@ -0,0 +1,14 @@
1
+ from querygraph.navigator import AiNavigator, NavigatorInput, NavigatorOutput
2
+ from querygraph.osi import OsiDocument
3
+ from querygraph.typedid import TypeDidAgent, TypeDidEnvelope
4
+ from querygraph.odrl_rights import OdrlRightsLayer
5
+
6
+ __all__ = [
7
+ "AiNavigator",
8
+ "NavigatorInput",
9
+ "OdrlRightsLayer",
10
+ "NavigatorOutput",
11
+ "OsiDocument",
12
+ "TypeDidAgent",
13
+ "TypeDidEnvelope",
14
+ ]
@@ -0,0 +1,4 @@
1
+ from querygraph.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Callable
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from querygraph.typedid import AgentResponse, GovernedPrompt, TypeDidAgent
8
+
9
+
10
+ class TypeDidAgentRun(BaseModel):
11
+ supervisor: TypeDidAgent
12
+ specialists: list[TypeDidAgent]
13
+ prompt: GovernedPrompt
14
+ responses: list[AgentResponse] = Field(default_factory=list)
15
+
16
+ def aggregate(self) -> dict[str, Any]:
17
+ allowed = [response for response in self.responses if response.status == "allowed"]
18
+ denied = [response for response in self.responses if response.status == "denied"]
19
+ return {
20
+ "supervisor": self.supervisor.name,
21
+ "question": self.prompt.question,
22
+ "allowedSummaries": [response.summary for response in allowed],
23
+ "denials": [response.summary for response in denied],
24
+ "evidenceHashes": [
25
+ response.envelope.payload_sha256 for response in self.responses
26
+ ],
27
+ }
28
+
29
+
30
+ def deterministic_specialist(
31
+ agent: TypeDidAgent,
32
+ *,
33
+ summary: str,
34
+ status: str = "allowed",
35
+ evidence: list[str] | None = None,
36
+ redactions: list[str] | None = None,
37
+ ) -> Callable[[dict[str, Any]], AgentResponse]:
38
+ def invoke(payload: dict[str, Any]) -> AgentResponse:
39
+ supervisor = TypeDidAgent.new("SupervisorAgent")
40
+ request = supervisor.request(
41
+ agent,
42
+ action=payload.get("action", "summarize"),
43
+ resource=payload.get("resource", "qg_lakehouse"),
44
+ payload=payload,
45
+ )
46
+ return agent.answer(
47
+ request,
48
+ status="allowed" if status == "allowed" else "denied",
49
+ summary=summary,
50
+ evidence=evidence or [payload.get("resource", "qg_lakehouse")],
51
+ redactions=redactions or [],
52
+ )
53
+
54
+ return invoke
55
+
56
+
57
+ class TypeDidLangChainToolAdapter:
58
+ """Small adapter that exposes a TypeDID agent as a LangChain StructuredTool."""
59
+
60
+ def __init__(
61
+ self,
62
+ agent: TypeDidAgent,
63
+ handler: Callable[[dict[str, Any]], AgentResponse],
64
+ ) -> None:
65
+ self.agent = agent
66
+ self.handler = handler
67
+
68
+ def as_tool(self):
69
+ try:
70
+ from langchain_core.tools import StructuredTool
71
+ except ImportError as exc: # pragma: no cover - depends on optional extra.
72
+ raise RuntimeError(
73
+ "Install querygraph[agents] to use LangChain tool adapters."
74
+ ) from exc
75
+
76
+ def run(question: str, resource: str = "qg_lakehouse") -> dict[str, Any]:
77
+ response = self.handler(
78
+ {"question": question, "resource": resource, "action": "summarize"}
79
+ )
80
+ return response.model_dump(mode="json")
81
+
82
+ return StructuredTool.from_function(
83
+ func=run,
84
+ name=self.agent.name,
85
+ description=(
86
+ f"Governed TypeDID tool for {self.agent.name}; returns a signed "
87
+ "summary or denial."
88
+ ),
89
+ )
@@ -0,0 +1,15 @@
1
+ ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
2
+
3
+
4
+ def b58encode(data: bytes) -> str:
5
+ if not data:
6
+ return ""
7
+
8
+ value = int.from_bytes(data, "big")
9
+ encoded = ""
10
+ while value:
11
+ value, remainder = divmod(value, 58)
12
+ encoded = ALPHABET[remainder] + encoded
13
+
14
+ leading_zeroes = len(data) - len(data.lstrip(b"\0"))
15
+ return "1" * leading_zeroes + encoded