@1kbirds/chidori 0.1.20 → 0.1.23

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.
@@ -5,9 +5,10 @@ use tonic::{Response, Status};
5
5
  use futures::executor;
6
6
  use futures::StreamExt;
7
7
  use pyo3::types::{PyDict, PyList, PyString};
8
- use pyo3::types::{PyBool, PyFloat, PyInt};
9
8
  use pyo3::prelude::*;
10
9
  use std::collections::HashMap;
10
+ use std::sync::{Arc};
11
+ use tokio::sync::Mutex;
11
12
  use std::time::Duration;
12
13
  use tokio::runtime::Runtime;
13
14
  use log::{debug, info};
@@ -21,6 +22,8 @@ use ::prompt_graph_core::proto2::serialized_value::Val;
21
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};
22
23
  use ::prompt_graph_core::utils::wasm_error::CoreError;
23
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};
24
27
 
25
28
  #[derive(Debug)]
26
29
  pub struct CoreErrorWrapper(CoreError);
@@ -84,12 +87,27 @@ impl Into<pyo3::PyResult<()>> for PyErrWrapper {
84
87
  }
85
88
  }
86
89
 
87
- pub struct PyExecutionStatus(Response<ExecutionStatus>);
90
+
91
+ pub struct PyExecutionStatus(ExecutionStatus);
88
92
 
89
93
 
90
94
  impl IntoPy<Py<PyAny>> for PyExecutionStatus {
91
95
  fn into_py(self, py: Python) -> Py<PyAny> {
92
- let PyExecutionStatus(resp) = self;
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;
93
111
  let exec_status = resp.into_inner();
94
112
  let dict = PyDict::new(py);
95
113
  dict.set_item("id", exec_status.id).unwrap();
@@ -223,6 +241,7 @@ fn pyany_to_serialized_value(p: &PyAny) -> SerializedValue {
223
241
  "float" => {
224
242
  let val = p.extract::<f32>().unwrap();
225
243
  SerializedValue {
244
+ // file: Some(File {
226
245
  val: Some(Val::Float(val)),
227
246
  }
228
247
  }
@@ -267,6 +286,36 @@ fn pyany_to_serialized_value(p: &PyAny) -> SerializedValue {
267
286
  }
268
287
 
269
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
+
270
319
 
271
320
  fn dict_to_paths<'p>(
272
321
  py: Python<'p>,
@@ -353,142 +402,80 @@ async fn get_client(url: String) -> Result<ExecutionRuntimeClient<tonic::transpo
353
402
  // TODO: return a handle to nodes so that we can understand and inspect them
354
403
  // TODO: include a __repr__ method on those nodes
355
404
 
356
-
357
- // TODO: add an api for wiring together a system ot nodes
358
- // TODO: require the description of the complete system, in order to avoid mutably handling changing edges
359
- // TODO: system description must be fully encapsulated in a single object and applied all at once
360
-
361
405
  #[pyclass]
362
406
  #[derive(Clone)]
363
- struct NodeHandle {
364
- url: String,
365
- file_id: String,
366
- node: Item,
367
- exec_status: ExecutionStatus,
368
- indiv: CleanIndividualNode
407
+ struct PyNodeHandle {
408
+ n: NodeHandle,
369
409
  }
370
410
 
371
- impl NodeHandle {
372
- fn from(url: String, file_id: String, node: Item, exec_status: ExecutionStatus) -> anyhow::Result<NodeHandle> {
373
- let indiv = derive_for_individual_node(&node)?;
374
- Ok(NodeHandle {
375
- url,
376
- file_id,
377
- node,
378
- exec_status,
379
- indiv
380
- })
411
+ impl PyNodeHandle {
412
+ fn from(node_handle: NodeHandle) -> anyhow::Result<PyNodeHandle> {
413
+ Ok(PyNodeHandle { n: node_handle })
381
414
  }
382
415
  }
383
416
 
384
417
  #[pymethods]
385
- impl NodeHandle {
418
+ impl PyNodeHandle {
386
419
  fn get_name(&self) -> String {
387
- self.node.core.as_ref().unwrap().name.clone()
420
+ self.n.get_name()
388
421
  }
389
422
 
390
423
  /// This updates the definition of this node to query for the target NodeHandle's output. Moving forward
391
424
  /// it will execute whenever the target node resolves.
392
- #[pyo3(signature = (node_handle=None))]
393
- fn run_when<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, node_handle: Option<NodeHandle>) -> PyResult<&'a PyAny> {
394
- let file_id = self_.file_id.clone();
395
- let url = self_.url.clone();
396
- let mut node = self_.node.clone();
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);
397
428
  pyo3_asyncio::tokio::future_into_py(py, async move {
398
- // TODO: scan the queries and don't insert if the query already exists
399
- if let Some(node_handle) = node_handle {
400
- let queries = &mut node.core.as_mut().unwrap().queries;
401
- let q = construct_query_from_output_type(
402
- &node_handle.get_name(),
403
- &node_handle.get_name(),
404
- &node_handle.indiv.output_path
405
- ).map_err(AnyhowErrWrapper)?;
406
- queries.push(Query { query: Some(q)});
407
- Ok(push_file_merge(&url, &file_id, node).await?)
408
- } else {
409
- Err(PyErr::new::<PyTypeError, _>("node_handle must be a NodeHandle"))
410
- }
429
+ let mut graph_builder = g.lock().await;
430
+ Ok(n.run_when(&mut graph_builder, &other_node_handle.n)
431
+ .map_err(AnyhowErrWrapper)?)
411
432
  })
412
433
  }
413
434
 
414
- #[pyo3(signature = (branch=0, frame=0))]
415
- fn query<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, branch: u64, frame: u64) -> PyResult<&'a PyAny> {
416
- let file_id = self_.file_id.clone();
417
- let url = self_.url.clone();
418
- let name = self_.get_name();
419
-
420
- let query = construct_query_from_output_type(&name, &name, &self_.indiv.output_path)
421
- .map_err(AnyhowErrWrapper)?;
422
-
423
- // TODO: we need this to watch for changes to the query instead
424
- // TODO: or this should await until either the target counter has elapsed or the query has resulted
425
-
426
- pyo3_asyncio::tokio::future_into_py(py, async move {
427
- let mut client = get_client(url).await?;
428
- Ok(PyQueryAtFrameResponse(client.run_query(QueryAtFrame {
429
- id: file_id,
430
- query: Some(Query {
431
- query: Some(query)
432
- }),
433
- frame,
434
- branch,
435
- }).await.map_err(PyErrWrapper::from)?))
436
- })
437
- }
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
+ // }
438
442
 
439
443
  fn __str__(&self) -> PyResult<String> {
440
444
  // TODO: best practice is that these could be used to re-construct the same object
441
445
  let name = self.get_name();
442
- Ok(format!("NodeHandle(file_id={}, node={})", self.file_id, name))
446
+ Ok(format!("NodeHandle(node={})", name))
443
447
  }
444
448
 
445
449
  fn __repr__(&self) -> PyResult<String> {
446
450
  let name = self.get_name();
447
- Ok(format!("NodeHandle(file_id={}, node={})", self.file_id, name))
451
+ Ok(format!("NodeHandle(node={})", name))
448
452
  }
449
453
  }
450
454
 
451
455
 
452
456
  // TODO: all operations only apply to a specific branch at a time
453
457
  // TODO: maintain an internal map of the generated change responses for node additions to the associated query necessary to get that result
454
- #[pyclass]
455
- struct Chidori {
458
+ #[pyclass(name="Chidori")]
459
+ struct PyChidori {
460
+ c: Arc<Mutex<Chidori>>,
456
461
  file_id: String,
457
462
  current_head: u64,
458
463
  current_branch: u64,
459
464
  url: String
460
465
  }
461
466
 
462
-
463
-
464
- async fn push_file_merge(url: &String, file_id: &String, node: Item) -> Result<NodeHandle, PyErr> {
465
- let mut client = get_client(url.clone()).await?;
466
- let exec_status = client.merge(RequestFileMerge {
467
- id: file_id.clone(),
468
- file: Some(File {
469
- nodes: vec![node.clone()],
470
- ..Default::default()
471
- }),
472
- branch: 0,
473
- }).await.map_err(PyErrWrapper::from)?.into_inner();
474
- Ok(NodeHandle::from(
475
- url.clone(),
476
- file_id.clone(),
477
- node,
478
- exec_status
479
- ).map_err(AnyhowErrWrapper)?)
480
- }
481
-
482
467
  // TODO: internally all operations should have an assigned counter
483
468
  // we can keep the actual target counter hidden from the host sdk
484
469
  #[pymethods]
485
- impl Chidori {
470
+ impl PyChidori {
486
471
 
487
472
  #[new]
488
473
  #[pyo3(signature = (file_id=String::from("0"), url=String::from("http://127.0.0.1:9800"), api_token=None))]
489
474
  fn new(file_id: String, url: String, api_token: Option<String>) -> Self {
490
475
  debug!("Creating new Chidori instance with file_id={}, url={}, api_token={:?}", file_id, url, api_token);
491
- Chidori {
476
+ let c = Chidori::new(file_id.clone(), url.clone());
477
+ PyChidori {
478
+ c: Arc::new(Mutex::new(c)),
492
479
  file_id,
493
480
  current_head: 0,
494
481
  current_branch: 0,
@@ -497,32 +484,11 @@ impl Chidori {
497
484
  }
498
485
 
499
486
  fn start_server<'a>(mut self_: PyRefMut<'_, Self>, py: Python<'a>, file_path: Option<String>) -> PyResult<&'a PyAny> {
500
- let url_server = self_.url.clone();
501
- std::thread::spawn(move || {
502
- let result = run_server(url_server, file_path);
503
- match result {
504
- Ok(_) => { },
505
- Err(e) => {
506
- println!("Error running server: {}", e);
507
- },
508
- }
509
- });
510
-
487
+ let c = Arc::clone(&self_.c);
511
488
  let url = self_.url.clone();
512
489
  pyo3_asyncio::tokio::future_into_py(py, async move {
513
- 'retry: loop {
514
- let client = get_client(url.clone());
515
- match client.await {
516
- Ok(connection) => {
517
- eprintln!("Connection successfully established {:?}", &url);
518
- break 'retry
519
- },
520
- Err(e) => {
521
- eprintln!("Error connecting to server: {} with Error {}. Retrying...", &url, &e.0);
522
- std::thread::sleep(std::time::Duration::from_millis(1000));
523
- }
524
- }
525
- }
490
+ let c = c.lock().await;
491
+ c.start_server(file_path).await.map_err(AnyhowErrWrapper)?;
526
492
  Ok(())
527
493
  })
528
494
  }
@@ -533,7 +499,7 @@ impl Chidori {
533
499
  let url = self_.url.clone();
534
500
  pyo3_asyncio::tokio::future_into_py(py, async move {
535
501
  let mut client = get_client(url).await?;
536
- Ok(PyExecutionStatus(client.play(RequestAtFrame {
502
+ Ok(PyResponseExecutionStatus(client.play(RequestAtFrame {
537
503
  id: file_id,
538
504
  frame,
539
505
  branch,
@@ -549,7 +515,7 @@ impl Chidori {
549
515
  let branch = self_.current_branch.clone();
550
516
  pyo3_asyncio::tokio::future_into_py(py, async move {
551
517
  let mut client = get_client(url).await?;
552
- Ok(PyExecutionStatus(client.pause(RequestAtFrame {
518
+ Ok(PyResponseExecutionStatus(client.pause(RequestAtFrame {
553
519
  id: file_id,
554
520
  frame,
555
521
  branch,
@@ -570,7 +536,7 @@ impl Chidori {
570
536
  diverges_at_counter: 0,
571
537
  }).await.map_err(PyErrWrapper::from)?;
572
538
  // TODO: need to somehow handle writing to the current_branch
573
- Ok(PyExecutionStatus(result_branch))
539
+ Ok(PyResponseExecutionStatus(result_branch))
574
540
  })
575
541
  }
576
542
 
@@ -696,213 +662,147 @@ impl Chidori {
696
662
  })
697
663
  }
698
664
 
699
-
700
- // TODO: nodes that are added should return a clean definition of what their addition looks like
701
- // TODO: adding a node should also display any errors
702
- /// x = None
703
- /// with open("/Users/coltonpierson/Downloads/files_and_dirs.zip", "rb") as zip_file:
704
- /// contents = zip_file.read()
705
- /// x = await p.load_zip_file("LoadZip", """ output: String """, contents)
706
- /// x
707
- #[pyo3(signature = (name=String::new(), output_tables=vec![], output=String::new(), bytes=vec![]))]
708
- fn load_zip_file<'a>(
709
- mut self_: PyRefMut<'_, Self>,
710
- py: Python<'a>,
711
- name: String,
712
- output_tables: Vec<String>,
713
- output: String,
714
- bytes: Vec<u8>
715
- ) -> PyResult<&'a PyAny> {
716
- let file_id = self_.file_id.clone();
717
- let url = self_.url.clone();
718
- pyo3_asyncio::tokio::future_into_py(py, async move {
719
- let node = create_loader_node(
720
- name,
721
- vec![],
722
- output,
723
- LoadFrom::ZipfileBytes(bytes),
724
- output_tables
725
- );
726
- Ok(push_file_merge(&url, &file_id, node).await?)
727
- })
728
- }
729
-
730
- // TODO: nodes that are added should return a clean definition of what their addition looks like
731
- // TODO: adding a node should also display any errors
732
- #[pyo3(signature = (name=String::new(), queries=vec![None], output_tables=vec![], template=String::new(), model=String::from("GPT_3_5_TURBO")))]
733
- fn prompt_node<'a>(
665
+ pub fn register_custom_node_handle<'a>(
734
666
  mut self_: PyRefMut<'_, Self>,
735
667
  py: Python<'a>,
736
- name: String,
737
- queries: Vec<Option<String>>,
738
- output_tables: Vec<String>,
739
- template: String,
740
- model: String
668
+ key: String,
669
+ handler: PyObject
741
670
  ) -> PyResult<&'a PyAny> {
742
- let file_id = self_.file_id.clone();
743
- let url = self_.url.clone();
671
+ let c = Arc::clone(&self_.c);
672
+ let handler = Arc::new(handler);
744
673
  pyo3_asyncio::tokio::future_into_py(py, async move {
745
- let node = create_prompt_node(
746
- name,
747
- queries,
748
- template,
749
- model,
750
- output_tables
751
- ).map_err(PyErrWrapper::from)?;
752
- Ok(push_file_merge(&url, &file_id, node).await?)
753
- })
754
- }
755
-
756
- fn poll_local_code_node_execution<'a>(
757
- mut self_: PyRefMut<'_, Self>,
758
- py: Python<'a>,
759
- ) -> PyResult<&'a PyAny> {
760
- let file_id = self_.file_id.clone();
761
- let url = self_.url.clone();
762
-
763
- pyo3_asyncio::tokio::future_into_py(py, async move {
764
- let mut client = get_client(url).await?;
765
- let result = client.poll_node_will_execute_events(FilteredPollNodeWillExecuteEventsRequest {
766
- id: file_id.clone(),
767
- }).await.map_err(PyErrWrapper::from)?;
768
- debug!("poll_local_code_node_execution result = {:?}", result);
769
- Ok(PyRespondPollNodeWillExecuteEvents(result))
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(())
770
696
  })
771
697
  }
772
698
 
773
- #[pyo3(signature = (branch=0, counter=0))]
774
- fn ack_local_code_node_execution<'a>(
699
+ fn run_custom_node_loop<'a>(
775
700
  mut self_: PyRefMut<'_, Self>,
776
701
  py: Python<'a>,
777
- branch: u64,
778
- counter: u64,
779
702
  ) -> PyResult<&'a PyAny> {
780
- let file_id = self_.file_id.clone();
781
- let url = self_.url.clone();
703
+ let c = Arc::clone(&self_.c);
782
704
  pyo3_asyncio::tokio::future_into_py(py, async move {
783
- let mut client = get_client(url).await?;
784
- Ok(PyExecutionStatus(client.ack_node_will_execute_event(RequestAckNodeWillExecuteEvent {
785
- id: file_id.clone(),
786
- branch,
787
- counter,
788
- }).await.map_err(PyErrWrapper::from)?))
705
+ let mut c = c.lock().await;
706
+ Ok(c.run_custom_node_loop().await.map_err(AnyhowErrWrapper)?)
789
707
  })
790
708
  }
791
709
 
792
- #[pyo3(signature = (branch=0, counter=0, node_name=String::new(), response=None))]
793
- fn respond_local_code_node_execution<'a>(
794
- mut self_: PyRefMut<'_, Self>,
795
- py: Python<'a>,
796
- branch: u64,
797
- counter: u64,
798
- node_name: String,
799
- response: Option<PyObject>
800
- ) -> PyResult<&'a PyAny> {
801
-
802
- let file_id = self_.file_id.clone();
803
- let url = self_.url.clone();
804
-
805
- // TODO: need parent counters from the original change
806
- // TODO: need source node
807
710
 
808
- let response_paths = if let Some(response) = response {
809
- dict_to_paths(py, response.downcast::<PyDict>(py)?)?
810
- } else {
811
- vec![]
812
- };
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
+ }
813
730
 
814
- pyo3_asyncio::tokio::future_into_py(py, async move {
815
- let mut client = get_client(url).await?;
731
+ #[pyclass(name="GraphBuilder")]
732
+ #[derive(Clone)]
733
+ struct PyGraphBuilder {
734
+ g: Arc<Mutex<GraphBuilder>>,
735
+ }
816
736
 
817
- // TODO: need to add the output table paths to these
818
- let filled_values = response_paths.into_iter().map(|path| {
819
- ChangeValue {
820
- path: Some(Path {
821
- address: path.0,
822
- }),
823
- value: Some(path.1),
824
- branch,
825
- }
826
- });
737
+ #[pymethods]
738
+ impl PyGraphBuilder {
827
739
 
828
- // TODO: this needs to look more like a real change
829
- Ok(PyExecutionStatus(client.push_worker_event(FileAddressedChangeValueWithCounter {
830
- branch,
831
- counter,
832
- node_name,
833
- id: file_id.clone(),
834
- change: Some(ChangeValueWithCounter {
835
- filled_values: filled_values.collect(),
836
- parent_monotonic_counters: vec![],
837
- monotonic_counter: counter,
838
- branch,
839
- source_node: "".to_string(),
840
- })
841
- }).await.map_err(PyErrWrapper::from)?))
842
- })
740
+ #[new]
741
+ fn new() -> Self {
742
+ let g = GraphBuilder::new();
743
+ PyGraphBuilder {
744
+ g: Arc::new(Mutex::new(g)),
745
+ }
843
746
  }
844
747
 
845
- // TODO: handle dispatch to this handler - should accept a callback
846
748
  // https://github.com/PyO3/pyo3/issues/525
847
- #[pyo3(signature = (name=String::new(), queries=vec![None], output_tables=vec![], output=String::from("type O {}"), node_type_name=String::new()))]
749
+ #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=vec![], output=String::from("type O {}"), node_type_name=String::new()))]
848
750
  fn custom_node<'a>(
849
751
  mut self_: PyRefMut<'_, Self>,
850
752
  py: Python<'a>,
851
753
  name: String,
852
- queries: Vec<Option<String>>,
754
+ queries: Option<Vec<String>>,
853
755
  output_tables: Vec<String>,
854
756
  output: String,
855
757
  node_type_name: String,
856
758
  ) -> PyResult<&'a PyAny> {
857
- let file_id = self_.file_id.clone();
858
- let url = self_.url.clone();
859
- let branch = self_.current_branch;
759
+ let g = Arc::clone(&self_.g);
860
760
  pyo3_asyncio::tokio::future_into_py(py, async move {
861
- // Register the node with the system
862
- let node = create_custom_node(
761
+ let mut graph_builder = g.lock().await;
762
+ let nh = graph_builder.custom_node(CustomNodeCreateOpts {
863
763
  name,
864
764
  queries,
865
- output,
765
+ output_tables: Some(output_tables),
766
+ output: Some(output),
866
767
  node_type_name,
867
- output_tables
868
- );
869
- Ok(push_file_merge(&url, &file_id, node).await?)
768
+ }).map_err(AnyhowErrWrapper)?;
769
+ Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
870
770
  })
871
771
  }
872
772
 
873
- #[pyo3(signature = (name=String::new(), queries=vec![None], output_tables=vec![], output=String::from("type O { output: String }"), code=String::new(), is_template=false))]
773
+ #[pyo3(signature = (name=String::new(), queries=vec!["None".to_string()], output_tables=None, output=None, code=String::new(), is_template=None))]
874
774
  fn deno_code_node<'a>(
875
775
  mut self_: PyRefMut<'_, Self>,
876
776
  py: Python<'a>,
877
777
  name: String,
878
- queries: Vec<Option<String>>,
879
- output_tables: Vec<String>,
880
- output: String,
778
+ queries: Option<Vec<String>>,
779
+ output_tables: Option<Vec<String>>,
780
+ output: Option<String>,
881
781
  code: String,
882
- is_template: bool
782
+ is_template: Option<bool>
883
783
  ) -> PyResult<&'a PyAny> {
884
- let file_id = self_.file_id.clone();
885
- let url = self_.url.clone();
886
- let branch = self_.current_branch.clone();
784
+ let g = Arc::clone(&self_.g);
887
785
  pyo3_asyncio::tokio::future_into_py(py, async move {
888
- let node = create_code_node(
786
+ let mut graph_builder = g.lock().await;
787
+ let nh = graph_builder.deno_code_node(DenoCodeNodeCreateOpts {
889
788
  name,
890
789
  queries,
790
+ output_tables,
891
791
  output,
892
- SourceNodeType::Code("DENO".to_string(), code, is_template),
893
- output_tables
894
- );
895
- Ok(push_file_merge(&url, &file_id, node).await?)
792
+ code,
793
+ is_template,
794
+ }).map_err(AnyhowErrWrapper)?;
795
+ Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
896
796
  })
897
797
  }
898
798
 
899
799
 
900
- #[pyo3(signature = (name=String::new(), queries=vec![None], 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()))]
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()))]
901
801
  fn vector_memory_node<'a>(
902
802
  mut self_: PyRefMut<'_, Self>,
903
803
  py: Python<'a>,
904
804
  name: String,
905
- queries: Vec<Option<String>>,
805
+ queries: Option<Vec<String>>,
906
806
  output_tables: Vec<String>,
907
807
  output: String,
908
808
  template: String,
@@ -911,45 +811,98 @@ impl Chidori {
911
811
  db_vendor: String,
912
812
  collection_name: String,
913
813
  ) -> PyResult<&'a PyAny> {
914
- let file_id = self_.file_id.clone();
915
- let url = self_.url.clone();
916
- let branch = self_.current_branch.clone();
917
-
814
+ let g = Arc::clone(&self_.g);
918
815
  pyo3_asyncio::tokio::future_into_py(py, async move {
919
- let node = create_vector_memory_node(
816
+ let mut graph_builder = g.lock().await;
817
+ let nh = graph_builder.vector_memory_node(VectorMemoryNodeCreateOpts {
920
818
  name,
921
819
  queries,
922
- output,
923
- action,
924
- embedding_model,
925
- template,
926
- db_vendor,
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),
927
826
  collection_name,
928
- output_tables
929
- ).map_err(PyErrWrapper::from)?;
930
- Ok(push_file_merge(&url, &file_id, node).await?)
827
+ }).map_err(AnyhowErrWrapper)?;
828
+ Ok(PyNodeHandle::from(nh).map_err(AnyhowErrWrapper)?)
931
829
  })
932
830
  }
933
831
 
934
832
 
935
- //
936
- // fn observation_node(mut self_: PyRefMut<'_, Self>, name: String, query_def: Option<String>, template: String, model: String) -> PyResult<()> {
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> {
937
849
  // let file_id = self_.file_id.clone();
938
- // let node = create_observation_node(
939
- // "".to_string(),
940
- // None,
941
- // "".to_string(),
942
- // );
943
- // executor::block_on(self_.client.merge(RequestFileMerge {
944
- // id: file_id,
945
- // file: Some(File {
946
- // nodes: vec![node],
947
- // ..Default::default()
948
- // }),
949
- // branch: 0,
950
- // }));
951
- // Ok(())
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
+ // })
952
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
+ }
953
906
  }
954
907
 
955
908
 
@@ -959,7 +912,9 @@ impl Chidori {
959
912
  #[pymodule]
960
913
  #[pyo3(name = "chidori")]
961
914
  fn chidori(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
962
- pyo3_log::init();
963
- m.add_class::<Chidori>()?;
915
+ // pyo3_log::init();
916
+ m.add_class::<PyChidori>()?;
917
+ m.add_class::<PyGraphBuilder>()?;
964
918
  Ok(())
965
- }
919
+ }
920
+