@1kbirds/chidori 0.1.24 → 3.3.0

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 (39) hide show
  1. package/README.md +115 -5
  2. package/dist/agent.d.ts +487 -0
  3. package/dist/agent.js +46 -0
  4. package/dist/index.d.ts +332 -0
  5. package/dist/index.js +318 -0
  6. package/package.json +27 -32
  7. package/src/agent.ts +548 -0
  8. package/src/index.ts +580 -0
  9. package/.pytest_cache/README.md +0 -8
  10. package/CHANGELOG.md +0 -33
  11. package/Cargo.toml +0 -83
  12. package/build/stage/v0.1.24/chidori-v0.1.24-node-v108-darwin-arm64-unknown.tar.gz +0 -0
  13. package/build/stage/v0.1.24/chidori-v0.1.24-node-v93-darwin-arm64-unknown.tar.gz +0 -0
  14. package/build.rs +0 -7
  15. package/package_node/index.d.ts +0 -0
  16. package/package_node/index.js +0 -130
  17. package/package_node/native/chidori.node +0 -0
  18. package/package_python/.idea/inspectionProfiles/profiles_settings.xml +0 -6
  19. package/package_python/.idea/misc.xml +0 -4
  20. package/package_python/.idea/modules.xml +0 -8
  21. package/package_python/.idea/package_python.iml +0 -8
  22. package/package_python/.idea/vcs.xml +0 -6
  23. package/package_python/chidori/__init__.py +0 -0
  24. package/package_python/chidori/__pycache__/__init__.cpython-310.pyc +0 -0
  25. package/package_python/chidori/__pycache__/test_chidori.cpython-310-pytest-7.4.0.pyc +0 -0
  26. package/package_python/chidori/__pycache__/test_promptgraph.cpython-310-pytest-7.4.0.pyc +0 -0
  27. package/package_python/chidori/chidori.pyi +0 -32
  28. package/package_python/chidori/py.typed +0 -0
  29. package/package_python/chidori/test_chidori.py +0 -36
  30. package/pyproject.toml +0 -33
  31. package/src/lib.rs +0 -23
  32. package/src/translations/mod.rs +0 -9
  33. package/src/translations/nodejs.rs +0 -739
  34. package/src/translations/python.rs +0 -920
  35. package/src/translations/rust.rs +0 -737
  36. package/src/translations/shared.rs +0 -49
  37. package/src/translations/wasm.rs +0 -1
  38. package/tests/nodejs/chidori.test.js +0 -41
  39. package/tests/nodejs/nodeHandle.test.js +0 -15
@@ -1,920 +0,0 @@
1
- use std::collections::VecDeque;
2
- use pyo3::exceptions;
3
- use pyo3::prelude::*;
4
- use tonic::{Response, Status};
5
- use futures::executor;
6
- use futures::StreamExt;
7
- use pyo3::types::{PyDict, PyList, PyString};
8
- use pyo3::prelude::*;
9
- use std::collections::HashMap;
10
- use std::sync::{Arc};
11
- use tokio::sync::Mutex;
12
- use std::time::Duration;
13
- use tokio::runtime::Runtime;
14
- use log::{debug, info};
15
- use pyo3::exceptions::PyTypeError;
16
- use tonic::transport::Channel;
17
- use ::prompt_graph_exec::tonic_runtime::run_server;
18
- use ::prompt_graph_core::proto2::execution_runtime_client::ExecutionRuntimeClient;
19
- use ::prompt_graph_core::proto2::{File, Empty, ExecutionStatus, RequestInputProposalResponse, RequestOnlyId, RequestFileMerge, RequestAtFrame, RequestNewBranch, RequestListBranches, ListBranchesRes, QueryAtFrame, Query, QueryAtFrameResponse, SerializedValue, ChangeValueWithCounter, NodeWillExecuteOnBranch, FileAddressedChangeValueWithCounter, FilteredPollNodeWillExecuteEventsRequest, RespondPollNodeWillExecuteEvents, RequestAckNodeWillExecuteEvent, ChangeValue, Path, SerializedValueObject, SerializedValueArray, Item};
20
- use ::prompt_graph_core::proto2::prompt_graph_node_loader::LoadFrom;
21
- use ::prompt_graph_core::proto2::serialized_value::Val;
22
- use ::prompt_graph_core::graph_definition::{create_prompt_node, create_op_map, create_code_node, create_component_node, create_vector_memory_node, create_observation_node, create_node_parameter, SourceNodeType, create_loader_node, create_custom_node};
23
- use ::prompt_graph_core::utils::wasm_error::CoreError;
24
- use ::prompt_graph_core::build_runtime_graph::graph_parse::{CleanedDefinitionGraph, CleanIndividualNode, construct_query_from_output_type, derive_for_individual_node};
25
- use crate::register_node_handle;
26
- use crate::translations::rust::{Chidori, CustomNodeCreateOpts, DenoCodeNodeCreateOpts, GraphBuilder, Handler, NodeHandle, PromptNodeCreateOpts, VectorMemoryNodeCreateOpts};
27
-
28
- #[derive(Debug)]
29
- pub struct CoreErrorWrapper(CoreError);
30
-
31
- impl std::convert::From<CoreErrorWrapper> for PyErr {
32
- fn from(err: CoreErrorWrapper) -> PyErr {
33
- exceptions::PyOSError::new_err(err.0.to_string())
34
- }
35
- }
36
-
37
- impl std::convert::From<CoreError> for PyErrWrapper {
38
- fn from(err: CoreError) -> PyErrWrapper {
39
- PyErrWrapper(exceptions::PyOSError::new_err(err.to_string()))
40
- }
41
- }
42
-
43
- impl std::convert::From<anyhow::Error> for PyErrWrapper {
44
- fn from(err: anyhow::Error) -> PyErrWrapper {
45
- PyErrWrapper(exceptions::PyOSError::new_err(err.to_string()))
46
- }
47
- }
48
-
49
-
50
- #[derive(Debug)]
51
- pub struct PyErrWrapper(pyo3::PyErr);
52
-
53
- #[derive(Debug)]
54
- pub struct AnyhowErrWrapper(anyhow::Error);
55
-
56
-
57
- impl std::convert::From<tonic::transport::Error> for PyErrWrapper {
58
- fn from(status: tonic::transport::Error) -> Self {
59
- // Convert the `Status` to a `PyErr` here, then wrap it in `PyErrWrapper`.
60
- PyErrWrapper(exceptions::PyOSError::new_err(status.to_string()))
61
- }
62
- }
63
-
64
- impl std::convert::From<Status> for PyErrWrapper {
65
- fn from(status: Status) -> Self {
66
- // Convert the `Status` to a `PyErr` here, then wrap it in `PyErrWrapper`.
67
- PyErrWrapper(exceptions::PyOSError::new_err(status.message().to_string()))
68
- }
69
- }
70
-
71
-
72
- impl std::convert::From<PyErrWrapper> for PyErr {
73
- fn from(err: PyErrWrapper) -> PyErr {
74
- err.0
75
- }
76
- }
77
-
78
- impl std::convert::From<AnyhowErrWrapper> for PyErr {
79
- fn from(err: AnyhowErrWrapper) -> PyErr {
80
- exceptions::PyOSError::new_err(err.0.to_string())
81
- }
82
- }
83
-
84
- impl Into<pyo3::PyResult<()>> for PyErrWrapper {
85
- fn into(self) -> pyo3::PyResult<()> {
86
- Err(self.0)
87
- }
88
- }
89
-
90
-
91
- pub struct PyExecutionStatus(ExecutionStatus);
92
-
93
-
94
- impl IntoPy<Py<PyAny>> for PyExecutionStatus {
95
- fn into_py(self, py: Python) -> Py<PyAny> {
96
- let exec_status = self.0;
97
- let dict = PyDict::new(py);
98
- dict.set_item("id", exec_status.id).unwrap();
99
- dict.set_item("monotonic_counter", exec_status.monotonic_counter).unwrap();
100
- dict.set_item("branch", exec_status.branch).unwrap();
101
- dict.into_py(py)
102
- }
103
- }
104
-
105
- pub struct PyResponseExecutionStatus(Response<ExecutionStatus>);
106
-
107
-
108
- impl IntoPy<Py<PyAny>> for PyResponseExecutionStatus {
109
- fn into_py(self, py: Python) -> Py<PyAny> {
110
- let PyResponseExecutionStatus(resp) = self;
111
- let exec_status = resp.into_inner();
112
- let dict = PyDict::new(py);
113
- dict.set_item("id", exec_status.id).unwrap();
114
- dict.set_item("monotonic_counter", exec_status.monotonic_counter).unwrap();
115
- dict.set_item("branch", exec_status.branch).unwrap();
116
- dict.into_py(py)
117
- }
118
- }
119
-
120
-
121
- pub struct PyListBranchesRes(Response<ListBranchesRes>);
122
-
123
-
124
- impl IntoPy<Py<PyAny>> for PyListBranchesRes {
125
- fn into_py(self, py: Python) -> Py<PyAny> {
126
- let PyListBranchesRes(resp) = self;
127
- let branches = resp.into_inner();
128
- let branch_list = branches.branches.into_iter().map(|branch| {
129
- let mut dict = PyDict::new(py);
130
- dict.set_item("id", branch.id).unwrap();
131
- dict.set_item("diverges_at_counter", branch.diverges_at_counter).unwrap();
132
- dict.set_item("source_branch_ids", format!("{:?}", branch.source_branch_ids)).unwrap();
133
- dict
134
- }).collect::<Vec<_>>();
135
- PyList::new(py, branch_list).into_py(py)
136
- }
137
- }
138
-
139
-
140
- pub struct PyQueryAtFrameResponse(Response<QueryAtFrameResponse>);
141
-
142
- impl IntoPy<Py<PyAny>> for PyQueryAtFrameResponse {
143
- fn into_py(self, py: Python) -> Py<PyAny> {
144
- let PyQueryAtFrameResponse(resp) = self;
145
- let res = resp.into_inner();
146
-
147
- let mut dict = PyDict::new(py);
148
- res.values.into_iter().for_each(|value| {
149
- let c = value.change_value.unwrap();
150
- let k = c.path.unwrap().address.join(":");
151
- let v = c.value.unwrap();
152
- // TODO: SerializeValue to python
153
- dict.set_item(k, SerializedValueWrapper(v)).unwrap();
154
- });
155
- PyList::new(py, dict).into_py(py)
156
- }
157
- }
158
-
159
- #[derive(Debug)]
160
- pub struct SerializedValueWrapper(SerializedValue);
161
-
162
- impl ToPyObject for SerializedValueWrapper {
163
- fn to_object(&self, py: Python<'_>) -> PyObject {
164
- if let None = self.0.val {
165
- let x: Option<bool> = None;
166
- return x.into_py(py);
167
- }
168
- match self.0.val.as_ref().unwrap() {
169
- Val::Float(x) => { x.into_py(py) }
170
- Val::Number(x) => { x.into_py(py) }
171
- Val::String(x) => { x.into_py(py) }
172
- Val::Boolean(x) => { x.into_py(py) }
173
- Val::Array(val) => {
174
- let py_list = PyList::empty(py);
175
- for item in &val.values {
176
- py_list.append(SerializedValueWrapper(item.clone()).to_object(py)).unwrap();
177
- }
178
- py_list.into_py(py)
179
- }
180
- Val::Object(val) => {
181
- let py_dict = PyDict::new(py);
182
- for (key, value) in &val.values {
183
- py_dict.set_item(key, SerializedValueWrapper(value.clone()).to_object(py)).unwrap();
184
- }
185
- py_dict.into_py(py)
186
- }
187
- }
188
- }
189
- }
190
-
191
- #[derive(Debug)]
192
- pub struct ChangeValueWithCounterWrapper(ChangeValueWithCounter);
193
-
194
- impl IntoPy<Py<PyAny>> for ChangeValueWithCounterWrapper {
195
- fn into_py(self, py: Python) -> Py<PyAny> {
196
- let mut dict = PyDict::new(py);
197
- self.0.filled_values.into_iter().for_each(|c| {
198
- let k = c.path.map(|path| path.address.join(":"));
199
- let v = c.value;
200
- if let (Some(k), Some(v)) = (k, v) {
201
- dict.set_item(k, SerializedValueWrapper(v)).unwrap();
202
- }
203
- });
204
- PyList::new(py, dict).into_py(py)
205
- }
206
- }
207
-
208
- fn add_to_dict<'p>(
209
- py: Python<'p>,
210
- keys: &Vec<String>,
211
- value: PyObject,
212
- d: &'p PyDict,
213
- ) -> PyResult<()> {
214
- if keys.len() == 1 {
215
- d.set_item(keys[0].clone(), value)?;
216
- } else {
217
- let key = &keys[0];
218
- if d.contains(key)? {
219
- let nested_dict = d.get_item(key).unwrap().downcast::<PyDict>()?;
220
- add_to_dict(py, &keys[1..].to_vec(), value, &nested_dict)?;
221
- } else {
222
- let nested_dict = PyDict::new(py);
223
- d.set_item(key, &nested_dict)?;
224
- add_to_dict(py, &keys[1..].to_vec(), value, &nested_dict)?;
225
- }
226
- }
227
- Ok(())
228
- }
229
-
230
-
231
- fn pyany_to_serialized_value(p: &PyAny) -> SerializedValue {
232
- match p.get_type().name() {
233
- Ok(s) => {
234
- match s {
235
- "int" => {
236
- let val = p.extract::<i32>().unwrap();
237
- SerializedValue {
238
- val: Some(Val::Number(val)),
239
- }
240
- }
241
- "float" => {
242
- let val = p.extract::<f32>().unwrap();
243
- SerializedValue {
244
- // file: Some(File {
245
- val: Some(Val::Float(val)),
246
- }
247
- }
248
- "str" => {
249
- let val = p.extract::<String>().unwrap();
250
- SerializedValue {
251
- val: Some(Val::String(val)),
252
- }
253
- }
254
- "bool" => {
255
- let val = p.extract::<bool>().unwrap();
256
- SerializedValue {
257
- val: Some(Val::Boolean(val)),
258
- }
259
- }
260
- "list" => {
261
- let list = p.downcast::<PyList>().unwrap();
262
- let arr = list
263
- .iter()
264
- .map(|item| pyany_to_serialized_value(item))
265
- .collect();
266
- SerializedValue {
267
- val: Some(Val::Array(SerializedValueArray { values: arr } )),
268
- }
269
- }
270
- "dict" => {
271
- let dict = p.downcast::<PyDict>().unwrap();
272
- let mut map = HashMap::new();
273
- for (key, value) in dict {
274
- let key_string = key.extract::<String>().unwrap();
275
- map.insert(key_string, pyany_to_serialized_value(value));
276
- }
277
- SerializedValue {
278
- val: Some(Val::Object(SerializedValueObject { values: map })),
279
- }
280
- }
281
- _ => SerializedValue::default(),
282
- }
283
- }
284
- Err(_) => SerializedValue::default(),
285
- }
286
- }
287
-
288
-
289
- use pyo3::prelude::*;
290
- use pyo3::types::IntoPyDict;
291
- use serde_json::json;
292
-
293
- fn py_to_json<'p>(py: Python<'p>, v: &PyAny) -> serde_json::Value {
294
- if v.is_none() {
295
- json!(null)
296
- } else if let Ok(b) = v.extract::<bool>() {
297
- json!(b)
298
- } else if let Ok(i) = v.extract::<i64>() {
299
- json!(i)
300
- } else if let Ok(f) = v.extract::<f64>() {
301
- json!(f)
302
- } else if let Ok(dict) = v.extract::<HashMap<String, Py<PyAny>>>() {
303
- let mut m = serde_json::map::Map::new();
304
- for (key, value) in dict {
305
- m.insert(key, py_to_json(py, value.as_ref(py)));
306
- }
307
- json!(m)
308
- } else if let Ok(list) = v.extract::<Vec<Py<PyAny>>>() {
309
- let v: Vec<serde_json::Value> = list.iter().map(|p| py_to_json(py, p.as_ref(py))).collect();
310
- json!(v)
311
- } else if let Ok(s) = v.extract::<String>() {
312
- json!(s)
313
- } else {
314
- json!(null)
315
- }
316
- }
317
-
318
-
319
-
320
- fn dict_to_paths<'p>(
321
- py: Python<'p>,
322
- d: &'p PyDict
323
- ) -> PyResult<Vec<(Vec<String>, SerializedValue)>> {
324
- let mut paths = Vec::new();
325
- let mut queue: VecDeque<(Vec<String>, &'p PyDict)> = VecDeque::new();
326
- queue.push_back((Vec::new(), d));
327
-
328
- while let Some((mut path, dict)) = queue.pop_front() {
329
- for (key, val) in dict {
330
- let key_str = key.extract::<String>()?;
331
- path.push(key_str.clone());
332
- match val.downcast::<PyDict>() {
333
- Ok(sub_dict) => {
334
- queue.push_back((path.clone(), sub_dict));
335
- },
336
- Err(_) => {
337
- paths.push((path.clone(), pyany_to_serialized_value(val)));
338
- }
339
- }
340
- path.pop();
341
- }
342
- }
343
-
344
- Ok(paths)
345
- }
346
-
347
-
348
- #[derive(Debug)]
349
- pub struct NodeWillExecuteOnBranchWrapper(NodeWillExecuteOnBranch);
350
-
351
- impl ToPyObject for NodeWillExecuteOnBranchWrapper {
352
- fn to_object(&self, py: Python<'_>) -> PyObject {
353
- let NodeWillExecuteOnBranch { branch, counter, node, custom_node_type_name} = &self.0;
354
- let dict = PyDict::new(py);
355
- dict.set_item("branch", branch).unwrap();
356
- dict.set_item("counter", counter).unwrap();
357
- if let Some(node) = node {
358
- dict.set_item("node_name", &node.source_node).unwrap();
359
- dict.set_item("type_name", &custom_node_type_name).unwrap();
360
-
361
- let event_dict = PyDict::new(py);
362
- // TODO: this needs to be fixed
363
- for change in &node.change_values_used_in_execution {
364
- if let Some(v) = &change.change_value {
365
- match v {
366
- ChangeValue { path: Some(path), value: Some(value), .. } => {
367
- add_to_dict(
368
- py,
369
- &path.address,
370
- SerializedValueWrapper(value.clone()).to_object(py),
371
- &event_dict,
372
- ).unwrap();
373
- },
374
- _ => {}
375
- }
376
- }
377
- }
378
-
379
- dict.set_item("event", event_dict).unwrap();
380
- }
381
- dict.into_py(py)
382
- }
383
- }
384
-
385
- pub struct PyRespondPollNodeWillExecuteEvents(Response<RespondPollNodeWillExecuteEvents>);
386
-
387
- impl IntoPy<Py<PyAny>> for PyRespondPollNodeWillExecuteEvents {
388
- fn into_py(self, py: Python) -> Py<PyAny> {
389
- let PyRespondPollNodeWillExecuteEvents(resp) = self;
390
- let res = resp.into_inner();
391
- let RespondPollNodeWillExecuteEvents { node_will_execute_events } = res;
392
- let x: Vec<NodeWillExecuteOnBranchWrapper> = node_will_execute_events.iter().cloned().map(NodeWillExecuteOnBranchWrapper).collect();
393
- PyList::new(py, x).into_py(py)
394
- }
395
- }
396
-
397
-
398
- async fn get_client(url: String) -> Result<ExecutionRuntimeClient<tonic::transport::Channel>, PyErrWrapper> {
399
- ExecutionRuntimeClient::connect(url.clone()).await.map_err(PyErrWrapper::from)
400
- }
401
-
402
- // TODO: return a handle to nodes so that we can understand and inspect them
403
- // TODO: include a __repr__ method on those nodes
404
-
405
- #[pyclass]
406
- #[derive(Clone)]
407
- struct PyNodeHandle {
408
- n: NodeHandle,
409
- }
410
-
411
- impl PyNodeHandle {
412
- fn from(node_handle: NodeHandle) -> anyhow::Result<PyNodeHandle> {
413
- Ok(PyNodeHandle { n: node_handle })
414
- }
415
- }
416
-
417
- #[pymethods]
418
- impl PyNodeHandle {
419
- fn get_name(&self) -> String {
420
- self.n.get_name()
421
- }
422
-
423
- /// This updates the definition of this node to query for the target NodeHandle's output. Moving forward
424
- /// it will execute whenever the target node resolves.
425
- fn run_when<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, graph_builder: &mut PyGraphBuilder, other_node_handle: PyNodeHandle) -> PyResult<&'a PyAny> {
426
- let mut n = self_.n.clone();
427
- let g = Arc::clone(&graph_builder.g);
428
- pyo3_asyncio::tokio::future_into_py(py, async move {
429
- let mut graph_builder = g.lock().await;
430
- Ok(n.run_when(&mut graph_builder, &other_node_handle.n)
431
- .map_err(AnyhowErrWrapper)?)
432
- })
433
- }
434
-
435
- // #[pyo3(signature = (branch=0, frame=0))]
436
- // fn query<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, file_id: String, url: String, branch: u64, frame: u64) -> PyResult<&'a PyAny> {
437
- // pyo3_asyncio::tokio::future_into_py(py, async move {
438
- // Ok(PyQueryAtFrameResponse(self_.n.query(file_id, url, branch, frame)
439
- // .await.map_err(PyErrWrapper::from)?))
440
- // })
441
- // }
442
-
443
- fn __str__(&self) -> PyResult<String> {
444
- // TODO: best practice is that these could be used to re-construct the same object
445
- let name = self.get_name();
446
- Ok(format!("NodeHandle(node={})", name))
447
- }
448
-
449
- fn __repr__(&self) -> PyResult<String> {
450
- let name = self.get_name();
451
- Ok(format!("NodeHandle(node={})", name))
452
- }
453
- }
454
-
455
-
456
- // TODO: all operations only apply to a specific branch at a time
457
- // TODO: maintain an internal map of the generated change responses for node additions to the associated query necessary to get that result
458
- #[pyclass(name="Chidori")]
459
- struct PyChidori {
460
- c: Arc<Mutex<Chidori>>,
461
- file_id: String,
462
- current_head: u64,
463
- current_branch: u64,
464
- url: String
465
- }
466
-
467
- // TODO: internally all operations should have an assigned counter
468
- // we can keep the actual target counter hidden from the host sdk
469
- #[pymethods]
470
- impl PyChidori {
471
-
472
- #[new]
473
- #[pyo3(signature = (file_id=String::from("0"), url=String::from("http://127.0.0.1:9800"), api_token=None))]
474
- fn new(file_id: String, url: String, api_token: Option<String>) -> Self {
475
- debug!("Creating new Chidori instance with file_id={}, url={}, api_token={:?}", file_id, url, api_token);
476
- let c = Chidori::new(file_id.clone(), url.clone());
477
- PyChidori {
478
- c: Arc::new(Mutex::new(c)),
479
- file_id,
480
- current_head: 0,
481
- current_branch: 0,
482
- url,
483
- }
484
- }
485
-
486
- fn start_server<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, file_path: Option<String>) -> PyResult<&'a PyAny> {
487
- let c = Arc::clone(&self_.c);
488
- let url = self_.url.clone();
489
- pyo3_asyncio::tokio::future_into_py(py, async move {
490
- let c = c.lock().await;
491
- c.start_server(file_path).await.map_err(AnyhowErrWrapper)?;
492
- Ok(())
493
- })
494
- }
495
-
496
- #[pyo3(signature = (branch=0, frame=0))]
497
- fn play<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, branch: u64, frame: u64) -> PyResult<&'a PyAny> {
498
- let file_id = self_.file_id.clone();
499
- let url = self_.url.clone();
500
- pyo3_asyncio::tokio::future_into_py(py, async move {
501
- let mut client = get_client(url).await?;
502
- Ok(PyResponseExecutionStatus(client.play(RequestAtFrame {
503
- id: file_id,
504
- frame,
505
- branch,
506
- }).await.map_err(PyErrWrapper::from)?))
507
- })
508
- }
509
-
510
-
511
- #[pyo3(signature = (frame=0))]
512
- fn pause<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, frame: u64) -> PyResult<&'a PyAny> {
513
- let file_id = self_.file_id.clone();
514
- let url = self_.url.clone();
515
- let branch = self_.current_branch.clone();
516
- pyo3_asyncio::tokio::future_into_py(py, async move {
517
- let mut client = get_client(url).await?;
518
- Ok(PyResponseExecutionStatus(client.pause(RequestAtFrame {
519
- id: file_id,
520
- frame,
521
- branch,
522
- }).await.map_err(PyErrWrapper::from)?))
523
- })
524
- }
525
-
526
-
527
- fn branch<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>) -> PyResult<&'a PyAny> {
528
- let file_id = self_.file_id.clone();
529
- let url = self_.url.clone();
530
- let branch = self_.current_branch.clone();
531
- pyo3_asyncio::tokio::future_into_py(py, async move {
532
- let mut client = get_client(url).await?;
533
- let result_branch = client.branch(RequestNewBranch {
534
- id: file_id,
535
- source_branch_id: branch,
536
- diverges_at_counter: 0,
537
- }).await.map_err(PyErrWrapper::from)?;
538
- // TODO: need to somehow handle writing to the current_branch
539
- Ok(PyResponseExecutionStatus(result_branch))
540
- })
541
- }
542
-
543
- #[pyo3(signature = (query=String::new(), branch=0, frame=0))]
544
- fn query<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, query: String, branch: u64, frame: u64) -> PyResult<&'a PyAny> {
545
- let file_id = self_.file_id.clone();
546
- let url = self_.url.clone();
547
- pyo3_asyncio::tokio::future_into_py(py, async move {
548
- let mut client = get_client(url).await?;
549
- Ok(PyQueryAtFrameResponse(client.run_query(QueryAtFrame {
550
- id: file_id,
551
- query: Some(Query {
552
- query: Some(query)
553
- }),
554
- frame,
555
- branch,
556
- }).await.map_err(PyErrWrapper::from)?))
557
- })
558
- }
559
-
560
- fn list_branches<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>) -> PyResult<&'a PyAny> {
561
- let file_id = self_.file_id.clone();
562
- let url = self_.url.clone();
563
- pyo3_asyncio::tokio::future_into_py(py, async move {
564
- let mut client = get_client(url).await?;
565
- Ok(PyListBranchesRes(client.list_branches(RequestListBranches {
566
- id: file_id,
567
- }).await.map_err(PyErrWrapper::from)?))
568
- })
569
- }
570
-
571
- fn display_graph_structure<'a>(
572
- mut self_: PyRefMut<'_, Self>,
573
- py: Python<'a>
574
- ) -> PyResult<&'a PyAny> {
575
- let file_id = self_.file_id.clone();
576
- let url = self_.url.clone();
577
- let branch = self_.current_branch.clone();
578
- pyo3_asyncio::tokio::future_into_py(py, async move {
579
- let mut client = get_client(url).await?;
580
- let file = client.current_file_state(RequestOnlyId {
581
- id: file_id,
582
- branch
583
- }).await.map_err(PyErrWrapper::from)?;
584
- let mut file = file.into_inner();
585
- let mut g = CleanedDefinitionGraph::zero();
586
- g.merge_file(&mut file).unwrap();
587
- Ok(g.get_dot_graph())
588
- })
589
- }
590
-
591
- // TODO: some of these register handlers instead
592
- // TODO: list registered graphs should not stream
593
- // TODO: add a message that sends the current graph state
594
-
595
- fn list_registered_graphs<'a>(
596
- mut self_: PyRefMut<'_, Self>,
597
- py: Python<'a>
598
- ) -> PyResult<&'a PyAny> {
599
- let file_id = self_.file_id.clone();
600
- let url = self_.url.clone();
601
- pyo3_asyncio::tokio::future_into_py(py, async move {
602
- let mut client = get_client(url).await?;
603
- let resp = client.list_registered_graphs(Empty {
604
- }).await.map_err(PyErrWrapper::from)?;
605
- let mut stream = resp.into_inner();
606
- while let Some(x) = stream.next().await {
607
- // callback.call(py, (x,), None);
608
- info!("Registered Graph = {:?}", x);
609
- };
610
- Ok(())
611
- })
612
- }
613
-
614
- fn list_input_proposals<'a>(
615
- mut self_: PyRefMut<'_, Self>,
616
- py: Python<'a>,
617
- callback: PyObject
618
- ) -> PyResult<&'a PyAny> {
619
- let file_id = self_.file_id.clone();
620
- let url = self_.url.clone();
621
- let branch = self_.current_branch;
622
- pyo3_asyncio::tokio::future_into_py(py, async move {
623
- let mut client = get_client(url).await?;
624
- let resp = client.list_input_proposals(RequestOnlyId {
625
- id: file_id,
626
- branch,
627
- }).await.map_err(PyErrWrapper::from)?;
628
- let mut stream = resp.into_inner();
629
- while let Some(x) = stream.next().await {
630
- // callback.call(py, (x,), None);
631
- info!("InputProposals = {:?}", x);
632
- };
633
- Ok(())
634
- })
635
- }
636
-
637
- // fn respond_to_input_proposal(mut self_: PyRefMut<'_, Self>) -> PyResult<()> {
638
- // Ok(())
639
- // }
640
-
641
- // TODO: this is a successful callback example
642
- fn list_change_events<'a>(
643
- mut self_: PyRefMut<'_, Self>,
644
- py: Python<'a>,
645
- callback: PyObject
646
- ) -> PyResult<&'a PyAny> {
647
- let file_id = self_.file_id.clone();
648
- let url = self_.url.clone();
649
- let branch = self_.current_branch;
650
- pyo3_asyncio::tokio::future_into_py(py, async move {
651
- let mut client = get_client(url).await?;
652
- let resp = client.list_change_events(RequestOnlyId {
653
- id: file_id,
654
- branch,
655
- }).await.map_err(PyErrWrapper::from)?;
656
- let mut stream = resp.into_inner();
657
- while let Some(x) = stream.next().await {
658
- Python::with_gil(|py| pyo3_asyncio::tokio::into_future(callback.as_ref(py).call((x.map(ChangeValueWithCounterWrapper).map_err(PyErrWrapper::from)?,), None)?))?
659
- .await?;
660
- };
661
- Ok(())
662
- })
663
- }
664
-
665
- pub fn register_custom_node_handle<'a>(
666
- mut self_: PyRefMut<'_, Self>,
667
- py: Python<'a>,
668
- key: String,
669
- handler: PyObject
670
- ) -> PyResult<&'a PyAny> {
671
- let c = Arc::clone(&self_.c);
672
- let handler = Arc::new(handler);
673
- pyo3_asyncio::tokio::future_into_py(py, async move {
674
- let mut c = c.lock().await;
675
- c.register_custom_node_handle(key, Handler::new(
676
- move |n| {
677
- let handler_clone = Arc::clone(&handler);
678
- Box::pin(async move {
679
- let result = Python::with_gil(|py| {
680
- let fut = handler_clone.as_ref().call(py, (NodeWillExecuteOnBranchWrapper(n).to_object(py), ), None)?;
681
- pyo3_asyncio::tokio::into_future(fut.as_ref(py))
682
- })?.await;
683
- match result {
684
- Ok(py_obj) => {
685
- Python::with_gil(|py| {
686
- let json_value = py_to_json(py, py_obj.as_ref(py));
687
- Ok(json_value)
688
- })
689
- },
690
- Err(err) => Err(anyhow::Error::new(err)),
691
- }
692
- })
693
- }
694
- ));
695
- Ok(())
696
- })
697
- }
698
-
699
- fn run_custom_node_loop<'a>(
700
- mut self_: PyRefMut<'_, Self>,
701
- py: Python<'a>,
702
- ) -> PyResult<&'a PyAny> {
703
- let c = Arc::clone(&self_.c);
704
- pyo3_asyncio::tokio::future_into_py(py, async move {
705
- let mut c = c.lock().await;
706
- Ok(c.run_custom_node_loop().await.map_err(AnyhowErrWrapper)?)
707
- })
708
- }
709
-
710
-
711
- //
712
- // fn observation_node(mut self_: PyRefMut<'_, Self>, name: String, query_def: Option<String>, template: String, model: String) -> PyResult<()> {
713
- // let file_id = self_.file_id.clone();
714
- // let node = create_observation_node(
715
- // "".to_string(),
716
- // None,
717
- // "".to_string(),
718
- // );
719
- // executor::block_on(self_.client.merge(RequestFileMerge {
720
- // id: file_id,
721
- // file: Some(File {
722
- // nodes: vec![node],
723
- // ..Default::default()
724
- // }),
725
- // branch: 0,
726
- // }));
727
- // Ok(())
728
- // }
729
- }
730
-
731
- #[pyclass(name="GraphBuilder")]
732
- #[derive(Clone)]
733
- struct PyGraphBuilder {
734
- g: Arc<Mutex<GraphBuilder>>,
735
- }
736
-
737
- #[pymethods]
738
- impl PyGraphBuilder {
739
-
740
- #[new]
741
- fn new() -> Self {
742
- let g = GraphBuilder::new();
743
- PyGraphBuilder {
744
- g: Arc::new(Mutex::new(g)),
745
- }
746
- }
747
-
748
- // https://github.com/PyO3/pyo3/issues/525
749
- #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=vec![], output=String::from("type O {}"), node_type_name=String::new()))]
750
- fn custom_node<'a>(
751
- mut self_: PyRefMut<'_, Self>,
752
- py: Python<'a>,
753
- name: String,
754
- queries: Option<Vec<String>>,
755
- output_tables: Vec<String>,
756
- output: String,
757
- node_type_name: String,
758
- ) -> PyResult<&'a PyAny> {
759
- let g = Arc::clone(&self_.g);
760
- pyo3_asyncio::tokio::future_into_py(py, async move {
761
- let mut graph_builder = g.lock().await;
762
- let nh = graph_builder.custom_node(CustomNodeCreateOpts {
763
- name,
764
- queries,
765
- output_tables: Some(output_tables),
766
- output: Some(output),
767
- node_type_name,
768
- }).map_err(AnyhowErrWrapper)?;
769
- Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
770
- })
771
- }
772
-
773
- #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=None, output=None, code=String::new(), is_template=None))]
774
- fn deno_code_node<'a>(
775
- mut self_: PyRefMut<'_, Self>,
776
- py: Python<'a>,
777
- name: String,
778
- queries: Option<Vec<String>>,
779
- output_tables: Option<Vec<String>>,
780
- output: Option<String>,
781
- code: String,
782
- is_template: Option<bool>
783
- ) -> PyResult<&'a PyAny> {
784
- let g = Arc::clone(&self_.g);
785
- pyo3_asyncio::tokio::future_into_py(py, async move {
786
- let mut graph_builder = g.lock().await;
787
- let nh = graph_builder.deno_code_node(DenoCodeNodeCreateOpts {
788
- name,
789
- queries,
790
- output_tables,
791
- output,
792
- code,
793
- is_template,
794
- }).map_err(AnyhowErrWrapper)?;
795
- Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
796
- })
797
- }
798
-
799
-
800
- #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=vec![], output=String::from("type O { }"), template=String::new(), action="WRITE".to_string(), embedding_model="TEXT_EMBEDDING_ADA_002".to_string(), db_vendor="QDRANT".to_string(), collection_name=String::new()))]
801
- fn vector_memory_node<'a>(
802
- mut self_: PyRefMut<'_, Self>,
803
- py: Python<'a>,
804
- name: String,
805
- queries: Option<Vec<String>>,
806
- output_tables: Vec<String>,
807
- output: String,
808
- template: String,
809
- action: String, // READ / WRITE
810
- embedding_model: String,
811
- db_vendor: String,
812
- collection_name: String,
813
- ) -> PyResult<&'a PyAny> {
814
- let g = Arc::clone(&self_.g);
815
- pyo3_asyncio::tokio::future_into_py(py, async move {
816
- let mut graph_builder = g.lock().await;
817
- let nh = graph_builder.vector_memory_node(VectorMemoryNodeCreateOpts {
818
- name,
819
- queries,
820
- output_tables: Some(output_tables),
821
- output: Some(output),
822
- template: Some(template),
823
- action: Some(action),
824
- embedding_model: Some(embedding_model),
825
- db_vendor: Some(db_vendor),
826
- collection_name,
827
- }).map_err(AnyhowErrWrapper)?;
828
- Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
829
- })
830
- }
831
-
832
-
833
- // // TODO: nodes that are added should return a clean definition of what their addition looks like
834
- // // TODO: adding a node should also display any errors
835
- // /// x = None
836
- // /// with open("/Users/coltonpierson/Downloads/files_and_dirs.zip", "rb") as zip_file:
837
- // /// contents = zip_file.read()
838
- // /// x = await p.load_zip_file("LoadZip", """ output: String """, contents)
839
- // /// x
840
- // #[pyo3(signature = (name=String::new(), output_tables=vec![], output=String::new(), bytes=vec![]))]
841
- // fn load_zip_file<'a>(
842
- // mut self_: PyRefMut<'_, Self>,
843
- // py: Python<'a>,
844
- // name: String,
845
- // output_tables: Vec<String>,
846
- // output: String,
847
- // bytes: Vec<u8>
848
- // ) -> PyResult<&'a PyAny> {
849
- // let file_id = self_.file_id.clone();
850
- // let url = self_.url.clone();
851
- // pyo3_asyncio::tokio::future_into_py(py, async move {
852
- // let node = create_loader_node(
853
- // name,
854
- // vec![],
855
- // output,
856
- // LoadFrom::ZipfileBytes(bytes),
857
- // output_tables
858
- // );
859
- // Ok(push_file_merge(&url, &file_id, node).await?)
860
- // })
861
- // }
862
-
863
- // TODO: nodes that are added should return a clean definition of what their addition looks like
864
- // TODO: adding a node should also display any errors
865
- #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=None, template=String::new(), model=None))]
866
- fn prompt_node<'a>(
867
- mut self_: PyRefMut<'_, Self>,
868
- py: Python<'a>,
869
- name: String,
870
- queries: Option<Vec<String>>,
871
- output_tables: Option<Vec<String>>,
872
- template: String,
873
- model: Option<String>
874
- ) -> PyResult<&'a PyAny> {
875
- let g = Arc::clone(&self_.g);
876
- pyo3_asyncio::tokio::future_into_py(py, async move {
877
- let mut graph_builder = g.lock().await;
878
- let nh = graph_builder.prompt_node(PromptNodeCreateOpts {
879
- name,
880
- queries,
881
- output_tables,
882
- template,
883
- model,
884
- }).map_err(AnyhowErrWrapper)?;
885
- Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
886
- })
887
- }
888
-
889
- fn commit<'a>(
890
- mut self_: PyRefMut<'_, Self>,
891
- py: Python<'a>,
892
- c: PyRef<'_, PyChidori>,
893
- branch: u64
894
- ) -> PyResult<&'a PyAny> {
895
- let g = Arc::clone(&self_.g);
896
- let c = Arc::clone(&c.c);
897
- pyo3_asyncio::tokio::future_into_py(py, async move {
898
- let mut graph_builder = g.lock().await;
899
- let mut chidori = c.lock().await;
900
- let exec_status = graph_builder.commit(&chidori, branch).await
901
- .map(PyExecutionStatus)
902
- .map_err(AnyhowErrWrapper)?;
903
- Ok(exec_status)
904
- })
905
- }
906
- }
907
-
908
-
909
- /// A Python module implemented in Rust. The name of this function must match
910
- /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to
911
- /// import the module.
912
- #[pymodule]
913
- #[pyo3(name = "chidori")]
914
- fn chidori(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
915
- // pyo3_log::init();
916
- m.add_class::<PyChidori>()?;
917
- m.add_class::<PyGraphBuilder>()?;
918
- Ok(())
919
- }
920
-