trustgraph-cli 2.1.10__tar.gz → 2.1.12__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 (82) hide show
  1. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/PKG-INFO +1 -1
  2. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/pyproject.toml +1 -0
  3. trustgraph_cli-2.1.12/trustgraph/cli/query_graph.py +595 -0
  4. trustgraph_cli-2.1.12/trustgraph/cli_version.py +1 -0
  5. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/PKG-INFO +1 -1
  6. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/SOURCES.txt +1 -0
  7. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/entry_points.txt +1 -0
  8. trustgraph_cli-2.1.10/trustgraph/cli_version.py +0 -1
  9. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/README.md +0 -0
  10. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/setup.cfg +0 -0
  11. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/__init__.py +0 -0
  12. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/add_library_document.py +0 -0
  13. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_collection.py +0 -0
  14. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_config_item.py +0 -0
  15. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_flow_blueprint.py +0 -0
  16. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_kg_core.py +0 -0
  17. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_mcp_tool.py +0 -0
  18. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/delete_tool.py +0 -0
  19. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/dump_msgpack.py +0 -0
  20. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/dump_queues.py +0 -0
  21. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/get_config_item.py +0 -0
  22. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/get_document_content.py +0 -0
  23. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/get_flow_blueprint.py +0 -0
  24. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/get_kg_core.py +0 -0
  25. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/graph_to_turtle.py +0 -0
  26. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/init_pulsar_manager.py +0 -0
  27. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/init_trustgraph.py +0 -0
  28. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_agent.py +0 -0
  29. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_document_embeddings.py +0 -0
  30. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_document_rag.py +0 -0
  31. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_embeddings.py +0 -0
  32. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_graph_embeddings.py +0 -0
  33. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_graph_rag.py +0 -0
  34. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_llm.py +0 -0
  35. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_mcp_tool.py +0 -0
  36. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_nlp_query.py +0 -0
  37. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_prompt.py +0 -0
  38. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_row_embeddings.py +0 -0
  39. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_rows_query.py +0 -0
  40. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/invoke_structured_query.py +0 -0
  41. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/list_collections.py +0 -0
  42. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/list_config_items.py +0 -0
  43. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_doc_embeds.py +0 -0
  44. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_kg_core.py +0 -0
  45. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_knowledge.py +0 -0
  46. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_sample_documents.py +0 -0
  47. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_structured_data.py +0 -0
  48. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/load_turtle.py +0 -0
  49. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/put_config_item.py +0 -0
  50. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/put_flow_blueprint.py +0 -0
  51. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/put_kg_core.py +0 -0
  52. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/remove_library_document.py +0 -0
  53. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/save_doc_embeds.py +0 -0
  54. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/set_collection.py +0 -0
  55. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/set_mcp_tool.py +0 -0
  56. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/set_prompt.py +0 -0
  57. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/set_token_costs.py +0 -0
  58. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/set_tool.py +0 -0
  59. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_config.py +0 -0
  60. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_flow_blueprints.py +0 -0
  61. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_flow_state.py +0 -0
  62. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_flows.py +0 -0
  63. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_graph.py +0 -0
  64. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_kg_cores.py +0 -0
  65. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_library_documents.py +0 -0
  66. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_library_processing.py +0 -0
  67. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_mcp_tools.py +0 -0
  68. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_parameter_types.py +0 -0
  69. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_processor_state.py +0 -0
  70. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_prompts.py +0 -0
  71. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_token_costs.py +0 -0
  72. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_token_rate.py +0 -0
  73. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/show_tools.py +0 -0
  74. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/start_flow.py +0 -0
  75. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/start_library_processing.py +0 -0
  76. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/stop_flow.py +0 -0
  77. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/stop_library_processing.py +0 -0
  78. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/unload_kg_core.py +0 -0
  79. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph/cli/verify_system_status.py +0 -0
  80. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/dependency_links.txt +0 -0
  81. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/requires.txt +0 -0
  82. {trustgraph_cli-2.1.10 → trustgraph_cli-2.1.12}/trustgraph_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trustgraph-cli
3
- Version: 2.1.10
3
+ Version: 2.1.12
4
4
  Summary: TrustGraph provides a means to run a pipeline of flexible AI processing components in a flexible means to achieve a processing pipeline.
5
5
  Author-email: "trustgraph.ai" <security@trustgraph.ai>
6
6
  Project-URL: Homepage, https://github.com/trustgraph-ai/trustgraph
@@ -71,6 +71,7 @@ tg-show-config = "trustgraph.cli.show_config:main"
71
71
  tg-show-flow-blueprints = "trustgraph.cli.show_flow_blueprints:main"
72
72
  tg-show-flow-state = "trustgraph.cli.show_flow_state:main"
73
73
  tg-show-flows = "trustgraph.cli.show_flows:main"
74
+ tg-query-graph = "trustgraph.cli.query_graph:main"
74
75
  tg-show-graph = "trustgraph.cli.show_graph:main"
75
76
  tg-show-kg-cores = "trustgraph.cli.show_kg_cores:main"
76
77
  tg-show-library-documents = "trustgraph.cli.show_library_documents:main"
@@ -0,0 +1,595 @@
1
+ """
2
+ Query the triple store with pattern matching and configurable output formats.
3
+
4
+ Unlike tg-show-graph which dumps the entire graph, this tool enables selective
5
+ queries by specifying any combination of subject, predicate, object, and graph.
6
+
7
+ Auto-detection rules for values:
8
+ - Starts with http://, https://, urn:, or wrapped in <> -> IRI
9
+ - Starts with << -> quoted triple (Turtle-style)
10
+ - Anything else -> literal
11
+
12
+ Examples:
13
+ tg-query-graph -s "http://example.org/entity"
14
+ tg-query-graph -p "http://www.w3.org/2000/01/rdf-schema#label"
15
+ tg-query-graph -o "Marie Curie" --object-language en
16
+ tg-query-graph -o "<<http://ex.org/s http://ex.org/p http://ex.org/o>>"
17
+ """
18
+
19
+ import argparse
20
+ import json
21
+ import os
22
+ import sys
23
+ from trustgraph.api import Api
24
+
25
+ default_url = os.getenv("TRUSTGRAPH_URL", 'http://localhost:8088/')
26
+ default_user = 'trustgraph'
27
+ default_collection = 'default'
28
+ default_token = os.getenv("TRUSTGRAPH_TOKEN", None)
29
+
30
+
31
+ def parse_inline_quoted_triple(value):
32
+ """Parse inline Turtle-style quoted triple: <<s p o>>
33
+
34
+ Args:
35
+ value: String in format "<<subject predicate object>>"
36
+
37
+ Returns:
38
+ dict: Wire-format quoted triple term, or None if parsing fails
39
+ """
40
+ # Strip << and >> markers
41
+ inner = value[2:-2].strip()
42
+
43
+ # Split on whitespace, but respect quoted strings
44
+ # Simple approach: split and handle common cases
45
+ parts = []
46
+ current = ""
47
+ in_quotes = False
48
+ quote_char = None
49
+
50
+ for char in inner:
51
+ if char in ('"', "'") and not in_quotes:
52
+ in_quotes = True
53
+ quote_char = char
54
+ current += char
55
+ elif char == quote_char and in_quotes:
56
+ in_quotes = False
57
+ quote_char = None
58
+ current += char
59
+ elif char.isspace() and not in_quotes:
60
+ if current:
61
+ parts.append(current)
62
+ current = ""
63
+ else:
64
+ current += char
65
+
66
+ if current:
67
+ parts.append(current)
68
+
69
+ if len(parts) != 3:
70
+ raise ValueError(
71
+ f"Quoted triple must have exactly 3 parts (s p o), got {len(parts)}: {parts}"
72
+ )
73
+
74
+ s_val, p_val, o_val = parts
75
+
76
+ # Build the inner triple terms
77
+ s_term = build_term(s_val)
78
+ p_term = build_term(p_val)
79
+ o_term = build_term(o_val)
80
+
81
+ return {
82
+ "t": "t",
83
+ "tr": {
84
+ "s": s_term,
85
+ "p": p_term,
86
+ "o": o_term
87
+ }
88
+ }
89
+
90
+
91
+ def build_term(value, term_type=None, datatype=None, language=None):
92
+ """Build wire-format Term dict from CLI input.
93
+
94
+ Auto-detection rules (when term_type is None):
95
+ - Starts with http://, https://, urn: -> IRI
96
+ - Wrapped in <> (e.g., <http://...>) -> IRI (angle brackets stripped)
97
+ - Starts with << and ends with >> -> quoted triple
98
+ - Anything else -> literal
99
+
100
+ Args:
101
+ value: The term value
102
+ term_type: One of 'iri', 'literal', 'triple', or None for auto-detect
103
+ datatype: Datatype for literal objects (e.g., xsd:integer)
104
+ language: Language tag for literal objects (e.g., en)
105
+
106
+ Returns:
107
+ dict: Wire-format Term dict, or None if value is None
108
+ """
109
+ if value is None:
110
+ return None
111
+
112
+ # Auto-detect type if not specified
113
+ if term_type is None:
114
+ if value.startswith("<<") and value.endswith(">>"):
115
+ term_type = "triple"
116
+ elif value.startswith("<") and value.endswith(">") and not value.startswith("<<"):
117
+ # Angle-bracket wrapped IRI: <http://...>
118
+ value = value[1:-1] # Strip < and >
119
+ term_type = "iri"
120
+ elif value.startswith(("http://", "https://", "urn:")):
121
+ term_type = "iri"
122
+ else:
123
+ term_type = "literal"
124
+
125
+ if term_type == "iri":
126
+ # Strip angle brackets if present
127
+ if value.startswith("<") and value.endswith(">"):
128
+ value = value[1:-1]
129
+ return {"t": "i", "i": value}
130
+ elif term_type == "literal":
131
+ result = {"t": "l", "v": value}
132
+ if datatype:
133
+ result["dt"] = datatype
134
+ if language:
135
+ result["ln"] = language
136
+ return result
137
+ elif term_type == "triple":
138
+ # Check if it's inline Turtle-style
139
+ if value.startswith("<<") and value.endswith(">>"):
140
+ return parse_inline_quoted_triple(value)
141
+ else:
142
+ # Assume it's raw JSON (legacy support)
143
+ triple_data = json.loads(value)
144
+ return {"t": "t", "tr": triple_data}
145
+ else:
146
+ raise ValueError(f"Unknown term type: {term_type}")
147
+
148
+
149
+ def build_quoted_triple_term(qt_subject, qt_subject_type,
150
+ qt_predicate,
151
+ qt_object, qt_object_type,
152
+ qt_object_datatype, qt_object_language):
153
+ """Build a quoted triple term from --qt-* arguments.
154
+
155
+ Returns:
156
+ dict: Wire-format quoted triple term, or None if no qt args provided
157
+ """
158
+ # Check if any qt args were provided
159
+ if not any([qt_subject, qt_predicate, qt_object]):
160
+ return None
161
+
162
+ # Subject (IRI or nested triple)
163
+ s_term = build_term(qt_subject, term_type=qt_subject_type)
164
+
165
+ # Predicate (always IRI)
166
+ p_term = build_term(qt_predicate, term_type='iri')
167
+
168
+ # Object (IRI, literal, or nested triple)
169
+ o_term = build_term(
170
+ qt_object,
171
+ term_type=qt_object_type,
172
+ datatype=qt_object_datatype,
173
+ language=qt_object_language
174
+ )
175
+
176
+ return {
177
+ "t": "t",
178
+ "tr": {
179
+ "s": s_term,
180
+ "p": p_term,
181
+ "o": o_term
182
+ }
183
+ }
184
+
185
+
186
+ def format_term(term_dict):
187
+ """Format a term dict for display in space/pipe output formats.
188
+
189
+ Handles multiple wire format styles:
190
+ - Short form (send): {"t": "i", "i": "..."}, {"t": "l", "v": "..."}
191
+ - Long form (receive): {"type": "i", "iri": "..."}, {"type": "l", "value": "..."}
192
+ - Raw quoted triple: {"s": {...}, "p": {...}, "o": {...}} (no type wrapper)
193
+ - Stringified quoted triple in IRI: {"t": "i", "i": "{\"s\":...}"} (backend quirk)
194
+
195
+ Args:
196
+ term_dict: Wire-format term dict
197
+
198
+ Returns:
199
+ str: Formatted string representation
200
+ """
201
+ if not term_dict:
202
+ return ""
203
+
204
+ # Get type - handle both short and long form
205
+ t = term_dict.get("t") or term_dict.get("type")
206
+
207
+ if t == "i":
208
+ # IRI - handle both "i" and "iri" keys
209
+ iri_value = term_dict.get("i") or term_dict.get("iri", "")
210
+ # Check if IRI value is actually a stringified quoted triple (backend quirk)
211
+ if iri_value.startswith('{"s":') or iri_value.startswith("{\"s\":"):
212
+ try:
213
+ parsed = json.loads(iri_value)
214
+ if "s" in parsed and "p" in parsed and "o" in parsed:
215
+ # It's a stringified quoted triple - format it properly
216
+ s = format_term(parsed.get("s", {}))
217
+ p = format_term(parsed.get("p", {}))
218
+ o = format_term(parsed.get("o", {}))
219
+ return f"<<{s} {p} {o}>>"
220
+ except json.JSONDecodeError:
221
+ pass # Not valid JSON, treat as regular IRI
222
+ return iri_value
223
+ elif t == "l":
224
+ # Literal - handle both short and long form keys
225
+ value = term_dict.get("v") or term_dict.get("value", "")
226
+ result = f'"{value}"'
227
+ # Language tag
228
+ lang = term_dict.get("ln") or term_dict.get("language")
229
+ if lang:
230
+ result += f'@{lang}'
231
+ else:
232
+ # Datatype
233
+ dt = term_dict.get("dt") or term_dict.get("datatype")
234
+ if dt:
235
+ result += f'^^{dt}'
236
+ return result
237
+ elif t == "t":
238
+ # Quoted triple - handle both "tr" and "triple" keys
239
+ tr = term_dict.get("tr") or term_dict.get("triple", {})
240
+ s = format_term(tr.get("s", {}))
241
+ p = format_term(tr.get("p", {}))
242
+ o = format_term(tr.get("o", {}))
243
+ return f"<<{s} {p} {o}>>"
244
+ elif t is None and "s" in term_dict and "p" in term_dict and "o" in term_dict:
245
+ # Raw quoted triple without type wrapper (has s, p, o keys directly)
246
+ s = format_term(term_dict.get("s", {}))
247
+ p = format_term(term_dict.get("p", {}))
248
+ o = format_term(term_dict.get("o", {}))
249
+ return f"<<{s} {p} {o}>>"
250
+
251
+ return str(term_dict)
252
+
253
+
254
+ def output_space(triples, headers=False):
255
+ """Output triples in space-separated format."""
256
+ if headers:
257
+ print("subject predicate object")
258
+ for triple in triples:
259
+ s = format_term(triple.get("s", {}))
260
+ p = format_term(triple.get("p", {}))
261
+ o = format_term(triple.get("o", {}))
262
+ print(s, p, o)
263
+
264
+
265
+ def output_pipe(triples, headers=False):
266
+ """Output triples in pipe-separated format."""
267
+ if headers:
268
+ print("subject|predicate|object")
269
+ for triple in triples:
270
+ s = format_term(triple.get("s", {}))
271
+ p = format_term(triple.get("p", {}))
272
+ o = format_term(triple.get("o", {}))
273
+ print(f"{s}|{p}|{o}")
274
+
275
+
276
+ def output_json(triples):
277
+ """Output triples as a JSON array."""
278
+ print(json.dumps(triples, indent=2))
279
+
280
+
281
+ def output_jsonl(triples):
282
+ """Output triples as JSON Lines (one object per line)."""
283
+ for triple in triples:
284
+ print(json.dumps(triple))
285
+
286
+
287
+ def query_graph(
288
+ url, flow_id, user, collection, limit, batch_size,
289
+ subject=None, predicate=None, obj=None, graph=None,
290
+ output_format="space", headers=False, token=None
291
+ ):
292
+ """Query the triple store with pattern matching.
293
+
294
+ Uses the WebSocket API's raw streaming mode for efficient delivery of results.
295
+ """
296
+ socket = Api(url, token=token).socket()
297
+
298
+ # Build request dict directly (bypassing triples_query_stream's string conversion)
299
+ request = {
300
+ "user": user,
301
+ "collection": collection,
302
+ "limit": limit,
303
+ "streaming": True,
304
+ "batch-size": batch_size,
305
+ }
306
+
307
+ # Add term dicts for s/p/o (None means wildcard)
308
+ if subject is not None:
309
+ request["s"] = subject
310
+ if predicate is not None:
311
+ request["p"] = predicate
312
+ if obj is not None:
313
+ request["o"] = obj
314
+ if graph is not None:
315
+ request["g"] = graph
316
+
317
+ all_triples = []
318
+
319
+ try:
320
+ # Use raw streaming mode - yields response dicts directly
321
+ for response in socket._send_request_sync(
322
+ "triples", flow_id, request, streaming_raw=True
323
+ ):
324
+ # Response may have triples in different locations depending on format
325
+ if isinstance(response, dict):
326
+ triples = response.get("response", response.get("triples", []))
327
+ else:
328
+ triples = response
329
+
330
+ if not isinstance(triples, list):
331
+ triples = [triples] if triples else []
332
+
333
+ if output_format in ("json",):
334
+ # Collect all triples for JSON array output
335
+ all_triples.extend(triples)
336
+ else:
337
+ # Stream output for other formats
338
+ if output_format == "space":
339
+ output_space(triples, headers=headers and not all_triples)
340
+ elif output_format == "pipe":
341
+ output_pipe(triples, headers=headers and not all_triples)
342
+ elif output_format == "jsonl":
343
+ output_jsonl(triples)
344
+ # Track that we've output something (for headers logic)
345
+ all_triples.extend([None] * len(triples))
346
+
347
+ # Output collected JSON array
348
+ if output_format == "json":
349
+ output_json(all_triples)
350
+
351
+ finally:
352
+ socket.close()
353
+
354
+
355
+ def main():
356
+ parser = argparse.ArgumentParser(
357
+ prog='tg-query-graph',
358
+ description=__doc__,
359
+ formatter_class=argparse.RawDescriptionHelpFormatter,
360
+ )
361
+
362
+ # Outer triple filters
363
+ outer_group = parser.add_argument_group('Outer triple filters')
364
+
365
+ outer_group.add_argument(
366
+ '-s', '--subject',
367
+ metavar='VALUE',
368
+ help='Subject filter (auto-detected as IRI or literal)',
369
+ )
370
+
371
+ outer_group.add_argument(
372
+ '-p', '--predicate',
373
+ metavar='VALUE',
374
+ help='Predicate filter (auto-detected as IRI)',
375
+ )
376
+
377
+ outer_group.add_argument(
378
+ '-o', '--object',
379
+ dest='obj',
380
+ metavar='VALUE',
381
+ help='Object filter (IRI, literal, or <<quoted triple>>)',
382
+ )
383
+
384
+ outer_group.add_argument(
385
+ '--object-type',
386
+ choices=['iri', 'literal', 'triple'],
387
+ metavar='TYPE',
388
+ help='Override object type detection: iri, literal, triple',
389
+ )
390
+
391
+ outer_group.add_argument(
392
+ '--object-datatype',
393
+ metavar='DATATYPE',
394
+ help='Datatype for literal object (e.g., xsd:integer)',
395
+ )
396
+
397
+ outer_group.add_argument(
398
+ '--object-language',
399
+ metavar='LANG',
400
+ help='Language tag for literal object (e.g., en)',
401
+ )
402
+
403
+ outer_group.add_argument(
404
+ '-g', '--graph',
405
+ metavar='VALUE',
406
+ help='Named graph filter',
407
+ )
408
+
409
+ # Quoted triple filters (alternative to inline <<s p o>> syntax)
410
+ qt_group = parser.add_argument_group(
411
+ 'Quoted triple filters',
412
+ 'Build object as quoted triple using explicit fields (alternative to -o "<<s p o>>")'
413
+ )
414
+
415
+ qt_group.add_argument(
416
+ '--qt-subject',
417
+ metavar='VALUE',
418
+ help='Quoted triple subject',
419
+ )
420
+
421
+ qt_group.add_argument(
422
+ '--qt-subject-type',
423
+ choices=['iri', 'triple'],
424
+ metavar='TYPE',
425
+ help='Override qt-subject type: iri, triple',
426
+ )
427
+
428
+ qt_group.add_argument(
429
+ '--qt-predicate',
430
+ metavar='VALUE',
431
+ help='Quoted triple predicate (always IRI)',
432
+ )
433
+
434
+ qt_group.add_argument(
435
+ '--qt-object',
436
+ metavar='VALUE',
437
+ help='Quoted triple object',
438
+ )
439
+
440
+ qt_group.add_argument(
441
+ '--qt-object-type',
442
+ choices=['iri', 'literal', 'triple'],
443
+ metavar='TYPE',
444
+ help='Override qt-object type: iri, literal, triple',
445
+ )
446
+
447
+ qt_group.add_argument(
448
+ '--qt-object-datatype',
449
+ metavar='DATATYPE',
450
+ help='Datatype for qt-object literal',
451
+ )
452
+
453
+ qt_group.add_argument(
454
+ '--qt-object-language',
455
+ metavar='LANG',
456
+ help='Language tag for qt-object literal',
457
+ )
458
+
459
+ # Standard parameters
460
+ std_group = parser.add_argument_group('Standard parameters')
461
+
462
+ std_group.add_argument(
463
+ '-u', '--api-url',
464
+ default=default_url,
465
+ metavar='URL',
466
+ help=f'API URL (default: {default_url})',
467
+ )
468
+
469
+ std_group.add_argument(
470
+ '-f', '--flow-id',
471
+ default="default",
472
+ metavar='ID',
473
+ help='Flow ID (default: default)'
474
+ )
475
+
476
+ std_group.add_argument(
477
+ '-U', '--user',
478
+ default=default_user,
479
+ metavar='USER',
480
+ help=f'User/keyspace (default: {default_user})'
481
+ )
482
+
483
+ std_group.add_argument(
484
+ '-C', '--collection',
485
+ default=default_collection,
486
+ metavar='COLL',
487
+ help=f'Collection (default: {default_collection})'
488
+ )
489
+
490
+ std_group.add_argument(
491
+ '-t', '--token',
492
+ default=default_token,
493
+ metavar='TOKEN',
494
+ help='Auth token (default: $TRUSTGRAPH_TOKEN)',
495
+ )
496
+
497
+ std_group.add_argument(
498
+ '-l', '--limit',
499
+ type=int,
500
+ default=1000,
501
+ metavar='N',
502
+ help='Max results (default: 1000)',
503
+ )
504
+
505
+ std_group.add_argument(
506
+ '-b', '--batch-size',
507
+ type=int,
508
+ default=20,
509
+ metavar='N',
510
+ help='Streaming batch size (default: 20)',
511
+ )
512
+
513
+ # Output options
514
+ out_group = parser.add_argument_group('Output options')
515
+
516
+ out_group.add_argument(
517
+ '--format',
518
+ choices=['space', 'pipe', 'json', 'jsonl'],
519
+ default='space',
520
+ metavar='FORMAT',
521
+ help='Output format: space, pipe, json, jsonl (default: space)',
522
+ )
523
+
524
+ out_group.add_argument(
525
+ '-H', '--headers',
526
+ action='store_true',
527
+ help='Show column headers (for space/pipe formats)',
528
+ )
529
+
530
+ args = parser.parse_args()
531
+
532
+ try:
533
+ # Build term dicts from CLI arguments
534
+ subject_term = build_term(args.subject) if args.subject else None
535
+ predicate_term = build_term(args.predicate) if args.predicate else None
536
+
537
+ # Check for --qt-* args to build quoted triple as object
538
+ qt_term = build_quoted_triple_term(
539
+ qt_subject=args.qt_subject,
540
+ qt_subject_type=args.qt_subject_type,
541
+ qt_predicate=args.qt_predicate,
542
+ qt_object=args.qt_object,
543
+ qt_object_type=args.qt_object_type,
544
+ qt_object_datatype=args.qt_object_datatype,
545
+ qt_object_language=args.qt_object_language,
546
+ )
547
+
548
+ # Object: use --qt-* args if provided, otherwise use -o
549
+ if qt_term is not None:
550
+ if args.obj:
551
+ parser.error("Cannot use both -o/--object and --qt-* arguments")
552
+ obj_term = qt_term
553
+ elif args.obj:
554
+ obj_term = build_term(
555
+ args.obj,
556
+ term_type=args.object_type,
557
+ datatype=args.object_datatype,
558
+ language=args.object_language
559
+ )
560
+ else:
561
+ obj_term = None
562
+
563
+ # Graph is a plain IRI string, not a Term
564
+ # None = all graphs, "" = default graph only, "uri" = specific graph
565
+ graph_value = args.graph
566
+
567
+ query_graph(
568
+ url=args.api_url,
569
+ flow_id=args.flow_id,
570
+ user=args.user,
571
+ collection=args.collection,
572
+ limit=args.limit,
573
+ batch_size=args.batch_size,
574
+ subject=subject_term,
575
+ predicate=predicate_term,
576
+ obj=obj_term,
577
+ graph=graph_value,
578
+ output_format=args.format,
579
+ headers=args.headers,
580
+ token=args.token,
581
+ )
582
+
583
+ except json.JSONDecodeError as e:
584
+ print(f"Error parsing JSON: {e}", file=sys.stderr)
585
+ sys.exit(1)
586
+ except ValueError as e:
587
+ print(f"Error: {e}", file=sys.stderr)
588
+ sys.exit(1)
589
+ except Exception as e:
590
+ print(f"Exception: {e}", file=sys.stderr)
591
+ sys.exit(1)
592
+
593
+
594
+ if __name__ == "__main__":
595
+ main()
@@ -0,0 +1 @@
1
+ __version__ = "2.1.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: trustgraph-cli
3
- Version: 2.1.10
3
+ Version: 2.1.12
4
4
  Summary: TrustGraph provides a means to run a pipeline of flexible AI processing components in a flexible means to achieve a processing pipeline.
5
5
  Author-email: "trustgraph.ai" <security@trustgraph.ai>
6
6
  Project-URL: Homepage, https://github.com/trustgraph-ai/trustgraph
@@ -42,6 +42,7 @@ trustgraph/cli/load_turtle.py
42
42
  trustgraph/cli/put_config_item.py
43
43
  trustgraph/cli/put_flow_blueprint.py
44
44
  trustgraph/cli/put_kg_core.py
45
+ trustgraph/cli/query_graph.py
45
46
  trustgraph/cli/remove_library_document.py
46
47
  trustgraph/cli/save_doc_embeds.py
47
48
  trustgraph/cli/set_collection.py
@@ -38,6 +38,7 @@ tg-load-turtle = trustgraph.cli.load_turtle:main
38
38
  tg-put-config-item = trustgraph.cli.put_config_item:main
39
39
  tg-put-flow-blueprint = trustgraph.cli.put_flow_blueprint:main
40
40
  tg-put-kg-core = trustgraph.cli.put_kg_core:main
41
+ tg-query-graph = trustgraph.cli.query_graph:main
41
42
  tg-remove-library-document = trustgraph.cli.remove_library_document:main
42
43
  tg-save-doc-embeds = trustgraph.cli.save_doc_embeds:main
43
44
  tg-set-collection = trustgraph.cli.set_collection:main
@@ -1 +0,0 @@
1
- __version__ = "2.1.10"