graph-knowledge-doc-parser 0.1.0__py3-none-any.whl
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.
- graph_knowledge_doc_parser-0.1.0.dist-info/METADATA +326 -0
- graph_knowledge_doc_parser-0.1.0.dist-info/RECORD +38 -0
- graph_knowledge_doc_parser-0.1.0.dist-info/WHEEL +4 -0
- graph_knowledge_doc_parser-0.1.0.dist-info/entry_points.txt +3 -0
- kg_doc_parser/__init__.py +9 -0
- kg_doc_parser/cast_hinting.py +19 -0
- kg_doc_parser/document_ingester_logger.py +766 -0
- kg_doc_parser/models.py +277 -0
- kg_doc_parser/ocr.py +752 -0
- kg_doc_parser/pdf2png.py +286 -0
- kg_doc_parser/semantic_document_splitting_layerwise_edits.py +3302 -0
- kg_doc_parser/text_processing_utils.py +30 -0
- kg_doc_parser/utils/__init__.py +0 -0
- kg_doc_parser/utils/bounded_threadpool_executor.py +37 -0
- kg_doc_parser/utils/file_loaders.py +405 -0
- kg_doc_parser/utils/langchain.py +220 -0
- kg_doc_parser/utils/log.py +135 -0
- kg_doc_parser/utils/version_chaining.py +1278 -0
- kg_doc_parser/workflow_ingest/__init__.py +187 -0
- kg_doc_parser/workflow_ingest/_kogwistar.py +13 -0
- kg_doc_parser/workflow_ingest/adapters.py +212 -0
- kg_doc_parser/workflow_ingest/cache.py +63 -0
- kg_doc_parser/workflow_ingest/cli.py +324 -0
- kg_doc_parser/workflow_ingest/clients.py +444 -0
- kg_doc_parser/workflow_ingest/demo_harness.py +427 -0
- kg_doc_parser/workflow_ingest/design.py +208 -0
- kg_doc_parser/workflow_ingest/handlers.py +617 -0
- kg_doc_parser/workflow_ingest/models.py +575 -0
- kg_doc_parser/workflow_ingest/ocr_pipeline.py +1581 -0
- kg_doc_parser/workflow_ingest/page_index.py +473 -0
- kg_doc_parser/workflow_ingest/parser_core.py +862 -0
- kg_doc_parser/workflow_ingest/parsing.py +249 -0
- kg_doc_parser/workflow_ingest/probe.py +164 -0
- kg_doc_parser/workflow_ingest/providers.py +412 -0
- kg_doc_parser/workflow_ingest/runners.py +546 -0
- kg_doc_parser/workflow_ingest/semantics.py +231 -0
- kg_doc_parser/workflow_ingest/service.py +112 -0
- kg_doc_parser/workflow_ingest/smoke_assets.py +62 -0
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Execution clients for the workflow ingest pipeline.
|
|
4
|
+
|
|
5
|
+
This module keeps the execution surface explicit and testable:
|
|
6
|
+
- `DirectRuntimeIngestClient` runs the local workflow engine end-to-end.
|
|
7
|
+
- `ServerCanonicalKgClient` runs the workflow but hands canonical graph
|
|
8
|
+
persistence to an external server client.
|
|
9
|
+
- `DocumentTreeApiPersistenceClient` adapts the export bundle into the server
|
|
10
|
+
tree-upsert API payload.
|
|
11
|
+
|
|
12
|
+
The classes here are intentionally thin wrappers around the workflow runtime so
|
|
13
|
+
tests can swap transport and persistence behavior without changing workflow
|
|
14
|
+
logic.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from abc import ABC, abstractmethod
|
|
18
|
+
from typing import Any
|
|
19
|
+
from uuid import uuid4
|
|
20
|
+
|
|
21
|
+
from kogwistar.engine_core.models import Edge, Node
|
|
22
|
+
|
|
23
|
+
from .design import DEFAULT_WORKFLOW_ID, ensure_ingest_workflow_design
|
|
24
|
+
from .models import (
|
|
25
|
+
CanonicalGraphWriteResult,
|
|
26
|
+
IngestRunHandle,
|
|
27
|
+
IngestRunResult,
|
|
28
|
+
WorkflowExportBundle,
|
|
29
|
+
WorkflowIngestInput,
|
|
30
|
+
)
|
|
31
|
+
from .probe import emit_probe_event
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class UnsupportedClientOperation(RuntimeError):
|
|
35
|
+
"""Raised when a client path is intentionally not implemented."""
|
|
36
|
+
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class CanonicalGraphPersistenceClient(ABC):
|
|
41
|
+
"""Protocol for persisting an exported workflow graph bundle."""
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
def persist_graph_payload(self, bundle: WorkflowExportBundle) -> CanonicalGraphWriteResult:
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _jsonable_payload(value: Any) -> Any:
|
|
49
|
+
if hasattr(value, "model_dump"):
|
|
50
|
+
try:
|
|
51
|
+
return value.model_dump(field_mode="backend", dump_format="json")
|
|
52
|
+
except TypeError:
|
|
53
|
+
return value.model_dump()
|
|
54
|
+
if isinstance(value, dict):
|
|
55
|
+
return {str(k): _jsonable_payload(v) for k, v in value.items()}
|
|
56
|
+
if isinstance(value, list):
|
|
57
|
+
return [_jsonable_payload(item) for item in value]
|
|
58
|
+
if isinstance(value, tuple):
|
|
59
|
+
return [_jsonable_payload(item) for item in value]
|
|
60
|
+
return value
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _to_temp_id_graph_payload(graph_payload: dict[str, Any]) -> dict[str, Any]:
|
|
64
|
+
"""Adapt a canonical export bundle into the server's batch-temp-id contract."""
|
|
65
|
+
|
|
66
|
+
nodes = [_jsonable_payload(node) for node in graph_payload.get("nodes", [])]
|
|
67
|
+
edges = [_jsonable_payload(edge) for edge in graph_payload.get("edges", [])]
|
|
68
|
+
|
|
69
|
+
node_id_map: dict[str, str] = {}
|
|
70
|
+
for idx, node in enumerate(nodes, start=1):
|
|
71
|
+
original_id = str(node.get("id") or "")
|
|
72
|
+
temp_id = f"nn:{idx}"
|
|
73
|
+
if original_id:
|
|
74
|
+
node_id_map[original_id] = temp_id
|
|
75
|
+
node["id"] = temp_id
|
|
76
|
+
|
|
77
|
+
edge_id_map: dict[str, str] = {}
|
|
78
|
+
for idx, edge in enumerate(edges, start=1):
|
|
79
|
+
original_id = str(edge.get("id") or "")
|
|
80
|
+
temp_id = f"ne:{idx}"
|
|
81
|
+
if original_id:
|
|
82
|
+
edge_id_map[original_id] = temp_id
|
|
83
|
+
edge["id"] = temp_id
|
|
84
|
+
|
|
85
|
+
for edge in edges:
|
|
86
|
+
edge["source_ids"] = [node_id_map.get(str(x), str(x)) for x in edge.get("source_ids", [])]
|
|
87
|
+
edge["target_ids"] = [node_id_map.get(str(x), str(x)) for x in edge.get("target_ids", [])]
|
|
88
|
+
edge["source_edge_ids"] = [
|
|
89
|
+
edge_id_map.get(str(x), str(x)) for x in edge.get("source_edge_ids", []) or []
|
|
90
|
+
]
|
|
91
|
+
edge["target_edge_ids"] = [
|
|
92
|
+
edge_id_map.get(str(x), str(x)) for x in edge.get("target_edge_ids", []) or []
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
"doc_id": str(graph_payload.get("doc_id") or "workflow-ingest-doc"),
|
|
97
|
+
"insertion_method": str(graph_payload.get("insertion_method") or "workflow_ingest"),
|
|
98
|
+
"nodes": nodes,
|
|
99
|
+
"edges": edges,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class DocumentTreeApiPersistenceClient(CanonicalGraphPersistenceClient):
|
|
104
|
+
"""Bridge an export bundle to the server document-tree upsert endpoint."""
|
|
105
|
+
|
|
106
|
+
def __init__(
|
|
107
|
+
self,
|
|
108
|
+
*,
|
|
109
|
+
client: Any,
|
|
110
|
+
endpoint: str = "/api/document.upsert_tree",
|
|
111
|
+
base_url: str = "",
|
|
112
|
+
transport: str = "server_http_document_tree",
|
|
113
|
+
server_parser_used: bool = False,
|
|
114
|
+
) -> None:
|
|
115
|
+
self.client = client
|
|
116
|
+
self.endpoint = endpoint
|
|
117
|
+
self.base_url = base_url.rstrip("/")
|
|
118
|
+
self.transport = transport
|
|
119
|
+
self.server_parser_used = server_parser_used
|
|
120
|
+
|
|
121
|
+
def persist_graph_payload(self, bundle: WorkflowExportBundle) -> CanonicalGraphWriteResult:
|
|
122
|
+
payload = _to_temp_id_graph_payload(bundle.graph_payload)
|
|
123
|
+
endpoint = self.endpoint
|
|
124
|
+
if self.base_url and not endpoint.startswith("http://") and not endpoint.startswith("https://"):
|
|
125
|
+
endpoint = f"{self.base_url}{endpoint}"
|
|
126
|
+
response = self.client.post(endpoint, json=payload)
|
|
127
|
+
status_code = int(getattr(response, "status_code", 500))
|
|
128
|
+
if status_code >= 400:
|
|
129
|
+
body = getattr(response, "text", "")
|
|
130
|
+
raise RuntimeError(
|
|
131
|
+
f"canonical server persistence failed: status={status_code} body={body}"
|
|
132
|
+
)
|
|
133
|
+
response_json = response.json()
|
|
134
|
+
engine_result = response_json.get("engine_result") or {}
|
|
135
|
+
return CanonicalGraphWriteResult(
|
|
136
|
+
persistence_mode="server_canonical",
|
|
137
|
+
kg_authority="server",
|
|
138
|
+
canonical_write_confirmed=str(response_json.get("status") or "").lower() == "ok",
|
|
139
|
+
nodes_written=int(
|
|
140
|
+
engine_result.get("nodes_added")
|
|
141
|
+
or response_json.get("inserted_nodes")
|
|
142
|
+
or len(payload["nodes"])
|
|
143
|
+
),
|
|
144
|
+
edges_written=int(
|
|
145
|
+
engine_result.get("edges_added")
|
|
146
|
+
or response_json.get("inserted_edges")
|
|
147
|
+
or len(payload["edges"])
|
|
148
|
+
),
|
|
149
|
+
transport=self.transport,
|
|
150
|
+
server_parser_used=self.server_parser_used,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class IngestExecutionClient(ABC):
|
|
155
|
+
"""Shared ingest client contract used by direct and server-backed flows."""
|
|
156
|
+
|
|
157
|
+
@abstractmethod
|
|
158
|
+
def run_ingest(
|
|
159
|
+
self,
|
|
160
|
+
*,
|
|
161
|
+
inp: WorkflowIngestInput,
|
|
162
|
+
workflow_id: str = DEFAULT_WORKFLOW_ID,
|
|
163
|
+
deps: dict[str, Any] | None = None,
|
|
164
|
+
) -> IngestRunResult:
|
|
165
|
+
raise NotImplementedError
|
|
166
|
+
|
|
167
|
+
@abstractmethod
|
|
168
|
+
def resume_ingest(self, **kwargs) -> IngestRunResult:
|
|
169
|
+
raise NotImplementedError
|
|
170
|
+
|
|
171
|
+
@abstractmethod
|
|
172
|
+
def persist_graph_payload(self, bundle: WorkflowExportBundle) -> CanonicalGraphWriteResult:
|
|
173
|
+
raise NotImplementedError
|
|
174
|
+
|
|
175
|
+
@abstractmethod
|
|
176
|
+
def get_run_trace(self, *, run_id: str) -> list[Any]:
|
|
177
|
+
raise NotImplementedError
|
|
178
|
+
|
|
179
|
+
@abstractmethod
|
|
180
|
+
def get_latest_checkpoint(self, *, run_id: str) -> Any:
|
|
181
|
+
raise NotImplementedError
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class DirectRuntimeIngestClient(IngestExecutionClient):
|
|
185
|
+
"""Run ingest entirely against the local workflow and knowledge engines."""
|
|
186
|
+
|
|
187
|
+
def __init__(
|
|
188
|
+
self,
|
|
189
|
+
*,
|
|
190
|
+
workflow_engine,
|
|
191
|
+
conversation_engine,
|
|
192
|
+
knowledge_engine=None,
|
|
193
|
+
) -> None:
|
|
194
|
+
self.workflow_engine = workflow_engine
|
|
195
|
+
self.conversation_engine = conversation_engine
|
|
196
|
+
self.knowledge_engine = knowledge_engine
|
|
197
|
+
|
|
198
|
+
def run_ingest(
|
|
199
|
+
self,
|
|
200
|
+
*,
|
|
201
|
+
inp: WorkflowIngestInput,
|
|
202
|
+
workflow_id: str = DEFAULT_WORKFLOW_ID,
|
|
203
|
+
deps: dict[str, Any] | None = None,
|
|
204
|
+
) -> IngestRunResult:
|
|
205
|
+
ensure_ingest_workflow_design(self.workflow_engine, workflow_id=workflow_id)
|
|
206
|
+
from .service import build_runtime
|
|
207
|
+
|
|
208
|
+
probe = (deps or {}).get("probe")
|
|
209
|
+
runtime = build_runtime(
|
|
210
|
+
workflow_engine=self.workflow_engine,
|
|
211
|
+
conversation_engine=self.conversation_engine,
|
|
212
|
+
deps={
|
|
213
|
+
"knowledge_engine": self.knowledge_engine,
|
|
214
|
+
"persistence_mode": "local_debug",
|
|
215
|
+
"kg_authority": "local",
|
|
216
|
+
"graph_persistence_client": self,
|
|
217
|
+
**(deps or {}),
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
run_id = f"run|{inp.request_id}|{uuid4()}"
|
|
221
|
+
emit_probe_event(
|
|
222
|
+
probe,
|
|
223
|
+
"workflow.run_started",
|
|
224
|
+
request_id=inp.request_id,
|
|
225
|
+
workflow_id=workflow_id,
|
|
226
|
+
execution_mode="direct_runtime",
|
|
227
|
+
run_id=run_id,
|
|
228
|
+
)
|
|
229
|
+
run = runtime.run(
|
|
230
|
+
workflow_id=workflow_id,
|
|
231
|
+
conversation_id=f"ingest:{inp.request_id}",
|
|
232
|
+
turn_node_id=f"ingest:{inp.request_id}:turn:{uuid4()}",
|
|
233
|
+
initial_state={"input": inp.model_dump(field_mode="backend", dump_format="json")},
|
|
234
|
+
run_id=run_id,
|
|
235
|
+
)
|
|
236
|
+
bundle = None
|
|
237
|
+
if "export_bundle" in run.final_state:
|
|
238
|
+
bundle = WorkflowExportBundle.model_validate(run.final_state["export_bundle"])
|
|
239
|
+
emit_probe_event(
|
|
240
|
+
probe,
|
|
241
|
+
"workflow.run_finished",
|
|
242
|
+
request_id=inp.request_id,
|
|
243
|
+
workflow_id=workflow_id,
|
|
244
|
+
execution_mode="direct_runtime",
|
|
245
|
+
run_id=run.run_id,
|
|
246
|
+
status=run.status,
|
|
247
|
+
)
|
|
248
|
+
return IngestRunResult(
|
|
249
|
+
handle=IngestRunHandle(
|
|
250
|
+
run_id=run.run_id,
|
|
251
|
+
workflow_id=workflow_id,
|
|
252
|
+
execution_mode="direct_runtime",
|
|
253
|
+
),
|
|
254
|
+
status=run.status,
|
|
255
|
+
bundle=bundle,
|
|
256
|
+
final_state=dict(run.final_state),
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def resume_ingest(self, **kwargs) -> IngestRunResult:
|
|
260
|
+
from .service import build_runtime
|
|
261
|
+
|
|
262
|
+
deps = dict(kwargs.pop("deps", {}) or {})
|
|
263
|
+
probe = deps.get("probe")
|
|
264
|
+
runtime = build_runtime(
|
|
265
|
+
workflow_engine=self.workflow_engine,
|
|
266
|
+
conversation_engine=self.conversation_engine,
|
|
267
|
+
deps={
|
|
268
|
+
"knowledge_engine": self.knowledge_engine,
|
|
269
|
+
"persistence_mode": "local_debug",
|
|
270
|
+
"kg_authority": "local",
|
|
271
|
+
"graph_persistence_client": self,
|
|
272
|
+
**deps,
|
|
273
|
+
},
|
|
274
|
+
)
|
|
275
|
+
emit_probe_event(
|
|
276
|
+
probe,
|
|
277
|
+
"workflow.resume_started",
|
|
278
|
+
execution_mode="direct_runtime",
|
|
279
|
+
run_id=kwargs.get("run_id"),
|
|
280
|
+
)
|
|
281
|
+
resumed = runtime.resume_run(**kwargs)
|
|
282
|
+
bundle = None
|
|
283
|
+
if "export_bundle" in resumed.final_state:
|
|
284
|
+
bundle = WorkflowExportBundle.model_validate(resumed.final_state["export_bundle"])
|
|
285
|
+
workflow_id = kwargs.get("workflow_id", DEFAULT_WORKFLOW_ID)
|
|
286
|
+
emit_probe_event(
|
|
287
|
+
probe,
|
|
288
|
+
"workflow.resume_finished",
|
|
289
|
+
execution_mode="direct_runtime",
|
|
290
|
+
run_id=resumed.run_id,
|
|
291
|
+
status=resumed.status,
|
|
292
|
+
)
|
|
293
|
+
return IngestRunResult(
|
|
294
|
+
handle=IngestRunHandle(
|
|
295
|
+
run_id=resumed.run_id,
|
|
296
|
+
workflow_id=workflow_id,
|
|
297
|
+
execution_mode="direct_runtime",
|
|
298
|
+
),
|
|
299
|
+
status=resumed.status,
|
|
300
|
+
bundle=bundle,
|
|
301
|
+
final_state=dict(resumed.final_state),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
def persist_graph_payload(self, bundle: WorkflowExportBundle) -> CanonicalGraphWriteResult:
|
|
305
|
+
if self.knowledge_engine is None:
|
|
306
|
+
return CanonicalGraphWriteResult(
|
|
307
|
+
persistence_mode="local_debug",
|
|
308
|
+
kg_authority="local",
|
|
309
|
+
canonical_write_confirmed=False,
|
|
310
|
+
transport="direct_runtime",
|
|
311
|
+
server_parser_used=False,
|
|
312
|
+
)
|
|
313
|
+
nodes_written = 0
|
|
314
|
+
edges_written = 0
|
|
315
|
+
for node in bundle.graph_payload.get("nodes", []):
|
|
316
|
+
node_obj = node if isinstance(node, Node) else Node.model_validate(node)
|
|
317
|
+
if not self.knowledge_engine.persist.exists_node(str(node_obj.safe_get_id())):
|
|
318
|
+
self.knowledge_engine.write.add_node(node_obj)
|
|
319
|
+
nodes_written += 1
|
|
320
|
+
for edge in bundle.graph_payload.get("edges", []):
|
|
321
|
+
edge_obj = edge if isinstance(edge, Edge) else Edge.model_validate(edge)
|
|
322
|
+
if not self.knowledge_engine.persist.exists_edge(str(edge_obj.safe_get_id())):
|
|
323
|
+
self.knowledge_engine.write.add_edge(edge_obj)
|
|
324
|
+
edges_written += 1
|
|
325
|
+
return CanonicalGraphWriteResult(
|
|
326
|
+
persistence_mode="local_debug",
|
|
327
|
+
kg_authority="local",
|
|
328
|
+
canonical_write_confirmed=False,
|
|
329
|
+
nodes_written=nodes_written,
|
|
330
|
+
edges_written=edges_written,
|
|
331
|
+
transport="direct_runtime",
|
|
332
|
+
server_parser_used=False,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
def get_run_trace(self, *, run_id: str) -> list[Any]:
|
|
336
|
+
return list(
|
|
337
|
+
self.conversation_engine.read.get_nodes(
|
|
338
|
+
where={"$and": [{"entity_type": "workflow_step_exec"}, {"run_id": str(run_id)}]}
|
|
339
|
+
)
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
def get_latest_checkpoint(self, *, run_id: str) -> Any:
|
|
343
|
+
checkpoints = list(
|
|
344
|
+
self.conversation_engine.read.get_nodes(
|
|
345
|
+
where={"$and": [{"entity_type": "workflow_checkpoint"}, {"run_id": str(run_id)}]}
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
if not checkpoints:
|
|
349
|
+
return None
|
|
350
|
+
return max(checkpoints, key=lambda node: int(node.metadata["step_seq"]))
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class ServerCanonicalKgClient(IngestExecutionClient):
|
|
354
|
+
"""Run ingest locally but delegate canonical graph persistence to a server."""
|
|
355
|
+
|
|
356
|
+
def __init__(
|
|
357
|
+
self,
|
|
358
|
+
*,
|
|
359
|
+
workflow_engine,
|
|
360
|
+
conversation_engine,
|
|
361
|
+
persistence_client: CanonicalGraphPersistenceClient,
|
|
362
|
+
) -> None:
|
|
363
|
+
self.workflow_engine = workflow_engine
|
|
364
|
+
self.conversation_engine = conversation_engine
|
|
365
|
+
self.persistence_client = persistence_client
|
|
366
|
+
|
|
367
|
+
def run_ingest(
|
|
368
|
+
self,
|
|
369
|
+
*,
|
|
370
|
+
inp: WorkflowIngestInput,
|
|
371
|
+
workflow_id: str = DEFAULT_WORKFLOW_ID,
|
|
372
|
+
deps: dict[str, Any] | None = None,
|
|
373
|
+
) -> IngestRunResult:
|
|
374
|
+
ensure_ingest_workflow_design(self.workflow_engine, workflow_id=workflow_id)
|
|
375
|
+
from .service import build_runtime
|
|
376
|
+
|
|
377
|
+
probe = (deps or {}).get("probe")
|
|
378
|
+
runtime = build_runtime(
|
|
379
|
+
workflow_engine=self.workflow_engine,
|
|
380
|
+
conversation_engine=self.conversation_engine,
|
|
381
|
+
deps={
|
|
382
|
+
"knowledge_engine": None,
|
|
383
|
+
"persistence_mode": "server_canonical",
|
|
384
|
+
"kg_authority": "server",
|
|
385
|
+
"graph_persistence_client": self.persistence_client,
|
|
386
|
+
**(deps or {}),
|
|
387
|
+
},
|
|
388
|
+
)
|
|
389
|
+
run_id = f"run|{inp.request_id}|{uuid4()}"
|
|
390
|
+
emit_probe_event(
|
|
391
|
+
probe,
|
|
392
|
+
"workflow.run_started",
|
|
393
|
+
request_id=inp.request_id,
|
|
394
|
+
workflow_id=workflow_id,
|
|
395
|
+
execution_mode="server_canonical_client",
|
|
396
|
+
run_id=run_id,
|
|
397
|
+
)
|
|
398
|
+
run = runtime.run(
|
|
399
|
+
workflow_id=workflow_id,
|
|
400
|
+
conversation_id=f"ingest:{inp.request_id}",
|
|
401
|
+
turn_node_id=f"ingest:{inp.request_id}:turn:{uuid4()}",
|
|
402
|
+
initial_state={"input": inp.model_dump(field_mode="backend", dump_format="json")},
|
|
403
|
+
run_id=run_id,
|
|
404
|
+
)
|
|
405
|
+
bundle = None
|
|
406
|
+
if "export_bundle" in run.final_state:
|
|
407
|
+
bundle = WorkflowExportBundle.model_validate(run.final_state["export_bundle"])
|
|
408
|
+
emit_probe_event(
|
|
409
|
+
probe,
|
|
410
|
+
"workflow.run_finished",
|
|
411
|
+
request_id=inp.request_id,
|
|
412
|
+
workflow_id=workflow_id,
|
|
413
|
+
execution_mode="server_canonical_client",
|
|
414
|
+
run_id=run.run_id,
|
|
415
|
+
status=run.status,
|
|
416
|
+
)
|
|
417
|
+
return IngestRunResult(
|
|
418
|
+
handle=IngestRunHandle(
|
|
419
|
+
run_id=run.run_id,
|
|
420
|
+
workflow_id=workflow_id,
|
|
421
|
+
execution_mode="server_canonical_client",
|
|
422
|
+
),
|
|
423
|
+
status=run.status,
|
|
424
|
+
bundle=bundle,
|
|
425
|
+
final_state=dict(run.final_state),
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
def resume_ingest(self, **kwargs) -> IngestRunResult:
|
|
429
|
+
raise UnsupportedClientOperation(
|
|
430
|
+
"remote/server-backed runtime resume is not implemented in this repo"
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
def persist_graph_payload(self, bundle: WorkflowExportBundle) -> CanonicalGraphWriteResult:
|
|
434
|
+
return self.persistence_client.persist_graph_payload(bundle)
|
|
435
|
+
|
|
436
|
+
def get_run_trace(self, *, run_id: str) -> list[Any]:
|
|
437
|
+
raise UnsupportedClientOperation(
|
|
438
|
+
"server-backed trace retrieval is not implemented in this repo"
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
def get_latest_checkpoint(self, *, run_id: str) -> Any:
|
|
442
|
+
raise UnsupportedClientOperation(
|
|
443
|
+
"server-backed checkpoint retrieval is not implemented in this repo"
|
|
444
|
+
)
|