feat: compact trace (#384)

* feat: compact trace

* align with changes

* add deserialization

* add tests and deserializer

* fix bindings

* first draft

* mock time; update snapshots

* fix

* Node.js test fix

* fix merge

* fix utc override

* fix cross-env

* fix workflow

* fix

---------

Co-authored-by: bojancrevar <bojan.crevar@gorules.io>
This commit is contained in:
stefan-gorules
2025-08-25 12:33:07 +02:00
committed by GitHub
co-authored by bojancrevar
parent 4a59f222db
commit 80fe4021c2
76 changed files with 2929 additions and 965 deletions
+8 -6
View File
@@ -1,4 +1,4 @@
use anyhow::anyhow;
use anyhow::{anyhow, Context};
use either::Either;
use pyo3::types::PyDict;
use pyo3::{Bound, IntoPyObjectExt, Py, PyAny, PyObject, PyResult, Python};
@@ -26,15 +26,17 @@ impl PyCustomNode {
}
fn extract_custom_node_response(py: Python<'_>, result: PyObject) -> NodeResult {
let dict = result.extract::<Bound<'_, PyDict>>(py)?;
let response: NodeResponse = depythonize(&dict)?;
let dict = result
.extract::<Bound<'_, PyDict>>(py)
.context("Failed to extract response")?;
let response: NodeResponse = depythonize(&dict).context("Failed to depythonize response")?;
Ok(response)
}
impl CustomNodeAdapter for PyCustomNode {
async fn handle(&self, request: CustomNodeRequest) -> NodeResult {
let Some(callable) = &self.callback else {
return Err(anyhow!("Custom node handler not provided"));
return Err(anyhow!("Custom node handler not provided").into());
};
let maybe_result: PyResult<_> = Python::with_gil(|py| {
@@ -57,10 +59,10 @@ impl CustomNodeAdapter for PyCustomNode {
Ok(Either::Right(result_future))
});
match maybe_result? {
match maybe_result.context("Failed to run custom node handler")? {
Either::Left(result) => result,
Either::Right(future) => {
let result = future.await?;
let result = future.await.context("Failed to run custom node handler")?;
Python::with_gil(|py| extract_custom_node_response(py, result))
}
}
+4 -4
View File
@@ -77,12 +77,12 @@ impl PyZenDecision {
)
.await
.map(serde_json::to_value)
.map_err(|e| {
anyhow!(serde_json::to_string(&e).unwrap_or_else(|_| e.to_string()))
})
})
.await
.context("Failed to join threads")?
.map_err(|e| {
anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string()))
})?
.context("Failed to join threads")??
.context("Failed to serialize result")?;
Python::with_gil(|py| PyValue(value).into_py_any(py))
+6 -4
View File
@@ -152,12 +152,14 @@ impl PyZenEngine {
)
.await
.map(serde_json::to_value)
.map_err(|e| {
anyhow!(
serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string())
)
})
})
.await
.context("Failed to join threads")?
.map_err(|e| {
anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string()))
})?
.context("Failed to join threads")??
.context("Failed to serialize result")?;
Python::with_gil(|py| PyValue(value).into_py_any(py))
+2 -2
View File
@@ -102,7 +102,7 @@ impl From<NodeResponse> for PyNodeResponse {
fn from(value: NodeResponse) -> Self {
Self {
output: value.output.to_value(),
trace_data: value.trace_data,
trace_data: value.trace_data.map(|v| v.to_value()),
}
}
}
@@ -111,7 +111,7 @@ impl From<PyNodeResponse> for NodeResponse {
fn from(value: PyNodeResponse) -> Self {
Self {
output: value.output.into(),
trace_data: value.trace_data,
trace_data: value.trace_data.map(|v| v.into()),
}
}
}