| 165 | } |
| 166 | |
| 167 | fn stream_from_async_iter( |
| 168 | async_iter: Py<PyAny>, |
| 169 | ) -> FlowResult<Pin<Box<dyn Stream<Item = FlowResult<Json>> + Send>>> { |
| 170 | let (tx, rx) = tokio::sync::mpsc::channel::<FlowResult<Json>>(32); |
| 171 | let task_locals = Python::attach(|py| { |
| 172 | pyo3_async_runtimes::tokio::get_current_locals(py) |
| 173 | .map_err(|e: pyo3::PyErr| FlowError::Internal(e.to_string())) |
| 174 | })?; |
| 175 | |
| 176 | let async_iter = Arc::new(async_iter); |
| 177 | tokio::spawn(pyo3_async_runtimes::tokio::scope(task_locals, async move { |
| 178 | forward_async_iter(async_iter, tx).await; |
| 179 | })); |
| 180 | |
| 181 | let stream = tokio_stream::wrappers::ReceiverStream::new(rx); |
| 182 | Ok(Box::pin(stream) as Pin<Box<dyn Stream<Item = FlowResult<Json>> + Send>>) |
| 183 | } |
| 184 | |
| 185 | /// Wrap a Python callable `(str, Json) -> Json` for tool sanitize/intercept fns. |
| 186 | pub fn wrap_py_tool_fn(py_fn: Py<PyAny>) -> ToolSanitizeFn { |