@1kbirds/chidori 0.1.16 → 0.1.20

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.
package/Cargo.toml CHANGED
@@ -53,6 +53,8 @@ pyo3-log = { version = "0.8.2", optional = true }
53
53
 
54
54
  neon-serde3 = "0.10.0"
55
55
 
56
+ tracing = "0.1"
57
+
56
58
  [dependencies.prompt-graph-exec]
57
59
  path = "../prompt-graph-exec"
58
60
  version = "0.1.0"
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Chidori
2
+
3
+ ## Generating Python Client
4
+ - maturin develop --features python
5
+
6
+ ## Generating Nodejs Client
7
+ - npm run build-release
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@1kbirds/chidori",
3
- "version": "v0.1.16",
4
- "description": "Prompt Graph SDK",
3
+ "version": "v0.1.20",
4
+ "description": "Chidori is a library for building and running reactive AI agents.",
5
5
  "main": "package_node/index.js",
6
6
  "scripts": {
7
7
  "build": "cargo-cp-artifact -nc ./package_node/native/chidori.node -- cargo build --message-format=json-render-diagnostics --features nodejs",
@@ -29,5 +29,7 @@ async def test_simple_agent():
29
29
  )
30
30
  await client.play(0, 0)
31
31
  await pn.query(0, 100)
32
+ assert 1 == 1
33
+
32
34
 
33
35
 
@@ -788,20 +788,6 @@ impl Chidori {
788
788
  // // TODO: nodes that are added should return a clean definition of what their addition looks like
789
789
  // // TODO: adding a node should also display any errors
790
790
 
791
- fn obj_interface(mut cx: FunctionContext) -> JsResult<JsValue> {
792
- let arg0 = cx.argument::<JsValue>(0)?;
793
- let arg0_value: ExecutionStatus = match neon_serde3::from_value(&mut cx, arg0) {
794
- Ok(value) => value,
795
- Err(e) => {
796
- return cx.throw_error(e.to_string());
797
- }
798
- };
799
- println!("{:?}", &arg0_value);
800
-
801
- neon_serde3::to_value(&mut cx, &arg0_value)
802
- .or_else(|e| cx.throw_error(e.to_string()))
803
- }
804
-
805
791
 
806
792
  fn prompt_node(mut cx: FunctionContext) -> JsResult<JsPromise> {
807
793
  let channel = cx.channel();
@@ -1227,7 +1213,6 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
1227
1213
  cx.export_function("chidoriBranch", Chidori::branch)?;
1228
1214
  cx.export_function("chidoriQuery", Chidori::query)?;
1229
1215
  cx.export_function("chidoriGraphStructure", Chidori::display_graph_structure)?;
1230
- cx.export_function("chidoriObjInterface", Chidori::obj_interface)?;
1231
1216
  cx.export_function("chidoriCustomNode", Chidori::custom_node)?;
1232
1217
  cx.export_function("chidoriDenoCodeNode", Chidori::deno_code_node)?;
1233
1218
  cx.export_function("chidoriVectorMemoryNode", Chidori::vector_memory_node)?;
@@ -22,12 +22,6 @@ use ::prompt_graph_core::graph_definition::{create_prompt_node, create_op_map, c
22
22
  use ::prompt_graph_core::utils::wasm_error::CoreError;
23
23
  use ::prompt_graph_core::build_runtime_graph::graph_parse::{CleanedDefinitionGraph, CleanIndividualNode, construct_query_from_output_type, derive_for_individual_node};
24
24
 
25
- // https://pyo3.rs/v0.19.0/
26
-
27
- // https://chat.openai.com/c/4dfe5b29-0cd9-493f-be8f-9362d376e764
28
-
29
- // TODO: create worker object
30
-
31
25
  #[derive(Debug)]
32
26
  pub struct CoreErrorWrapper(CoreError);
33
27
 
@@ -43,6 +37,13 @@ impl std::convert::From<CoreError> for PyErrWrapper {
43
37
  }
44
38
  }
45
39
 
40
+ impl std::convert::From<anyhow::Error> for PyErrWrapper {
41
+ fn from(err: anyhow::Error) -> PyErrWrapper {
42
+ PyErrWrapper(exceptions::PyOSError::new_err(err.to_string()))
43
+ }
44
+ }
45
+
46
+
46
47
  #[derive(Debug)]
47
48
  pub struct PyErrWrapper(pyo3::PyErr);
48
49
 
@@ -869,7 +870,7 @@ impl Chidori {
869
870
  })
870
871
  }
871
872
 
872
- #[pyo3(signature = (name=String::new(), queries=vec![None], output_tables=vec![], output=String::from("type O { }"), code=String::new(), is_template=false))]
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))]
873
874
  fn deno_code_node<'a>(
874
875
  mut self_: PyRefMut<'_, Self>,
875
876
  py: Python<'a>,
@@ -1,177 +1,508 @@
1
+ use std::cell::RefCell;
2
+ use std::collections::{HashMap, VecDeque};
3
+ use std::hash::Hash;
4
+ use std::marker::PhantomData;
5
+ use anyhow::Error;
6
+ use futures::StreamExt;
7
+ use log::{debug, info};
8
+ use once_cell::sync::OnceCell;
9
+ use tokio::runtime::Runtime;
10
+ use prompt_graph_core::build_runtime_graph::graph_parse::{CleanedDefinitionGraph, CleanIndividualNode, construct_query_from_output_type, derive_for_individual_node};
11
+ use prompt_graph_core::graph_definition::{create_code_node, create_custom_node, create_prompt_node, create_vector_memory_node, SourceNodeType};
12
+ use prompt_graph_core::proto2::{ChangeValue, ChangeValueWithCounter, Empty, ExecutionStatus, File, FileAddressedChangeValueWithCounter, FilteredPollNodeWillExecuteEventsRequest, Item, ListBranchesRes, Path, Query, QueryAtFrame, QueryAtFrameResponse, RequestAckNodeWillExecuteEvent, RequestAtFrame, RequestFileMerge, RequestListBranches, RequestNewBranch, RequestOnlyId, RespondPollNodeWillExecuteEvents, SerializedValue, SerializedValueArray, SerializedValueObject};
13
+ use prompt_graph_core::proto2::execution_runtime_client::ExecutionRuntimeClient;
14
+ use prompt_graph_core::proto2::serialized_value::Val;
15
+ use prompt_graph_exec::tonic_runtime::run_server;
16
+ use neon_serde3;
17
+ use serde::{Deserialize, Serialize};
18
+ use tonic::Status;
1
19
 
2
- use anyhow::Result;
20
+ async fn get_client(url: String) -> Result<ExecutionRuntimeClient<tonic::transport::Channel>, tonic::transport::Error> {
21
+ ExecutionRuntimeClient::connect(url.clone()).await
22
+ }
3
23
 
4
- use prompt_graph_core::graph_definition::DefinitionGraph;
5
- use prompt_graph_core::build_runtime_graph::graph_parse::CleanedDefinitionGraph;
6
- use prompt_graph_core::proto2::execution_runtime_client::ExecutionRuntimeClient;
7
- use prompt_graph_core::proto2::RequestFileMerge;
24
+ struct Chidori {
25
+ file_id: String,
26
+ current_head: u64,
27
+ current_branch: u64,
28
+ url: String
29
+ }
8
30
 
31
+ impl Chidori {
9
32
 
10
- // TODO: need to define pattern for automatically wiring dependencies
11
- // TODO: add methods
12
- // create_entrypoint_query
33
+ fn new(file_id: String, url: String) -> Self {
34
+ if !url.contains("://") {
35
+ panic!("Invalid url, must include protocol");
36
+ }
37
+ // let api_token = cx.argument_opt(2)?.value(&mut cx);
38
+ debug!("Creating new Chidori instance with file_id={}, url={}, api_token={:?}", file_id, url, "".to_string());
39
+ Chidori {
40
+ file_id,
41
+ current_head: 0,
42
+ current_branch: 0,
43
+ url,
44
+ }
45
+ }
13
46
 
14
- pub fn new_graph() -> DefinitionGraph {
15
- DefinitionGraph::zero()
16
- }
47
+ async fn start_server(&self, file_path: Option<String>) -> anyhow::Result<()> {
48
+ let url_server = self.url.clone();
49
+ std::thread::spawn(move || {
50
+ let result = run_server(url_server, file_path);
51
+ match result {
52
+ Ok(_) => {
53
+ println!("Server exited");
54
+ },
55
+ Err(e) => {
56
+ println!("Error running server: {}", e);
57
+ },
58
+ }
59
+ });
17
60
 
18
- #[macro_export]
19
- macro_rules! register_all {
20
- ($graph:expr, $($statement:expr,)*) => {
21
- $( $graph.register_node($statement); )*
22
- };
61
+ let url = self.url.clone();
62
+ loop {
63
+ match get_client(url.clone()).await {
64
+ Ok(connection) => {
65
+ eprintln!("Connection successfully established {:?}", &url);
66
+ return Ok(());
67
+ },
68
+ Err(e) => {
69
+ eprintln!("Error connecting to server: {} with Error {}. Retrying...", &url, &e.to_string());
70
+ std::thread::sleep(std::time::Duration::from_millis(1000));
71
+ }
72
+ }
73
+ }
74
+ }
75
+
76
+ async fn play(&self, branch: u64, frame: u64) -> anyhow::Result<ExecutionStatus> {
77
+ let file_id = self.file_id.clone();
78
+ let url = self.url.clone();
79
+ let mut client = get_client(url).await?;
80
+ let result = client.play(RequestAtFrame {
81
+ id: file_id,
82
+ frame,
83
+ branch,
84
+ }).await?;
85
+ Ok(result.into_inner())
86
+ }
87
+
88
+ async fn pause(&self, frame: u64) -> anyhow::Result<ExecutionStatus> {
89
+ let file_id = self.file_id.clone();
90
+ let url = self.url.clone();
91
+ let branch = self.current_branch.clone();
92
+
93
+ let mut client = get_client(url).await?;
94
+ let result = client.pause(RequestAtFrame {
95
+ id: file_id,
96
+ frame,
97
+ branch,
98
+ }).await?;
99
+ Ok(result.into_inner())
100
+ }
101
+
102
+ async fn query( &self, query: String, branch: u64, frame: u64, ) -> anyhow::Result<QueryAtFrameResponse> {
103
+ let file_id = self.file_id.clone();
104
+ let url = self.url.clone();
105
+ let mut client = get_client(url).await?;
106
+ let result = client.run_query(QueryAtFrame {
107
+ id: file_id,
108
+ query: Some(Query {
109
+ query: Some(query)
110
+ }),
111
+ frame,
112
+ branch,
113
+ }).await?;
114
+ Ok(result.into_inner())
115
+ }
116
+
117
+ async fn list_branches( &self) -> anyhow::Result<ListBranchesRes> {
118
+ let file_id = self.file_id.clone();
119
+ let url = self.url.clone();
120
+ let mut client = get_client(url).await?;
121
+ let result = client.list_branches(RequestListBranches {
122
+ id: file_id,
123
+ }).await?;
124
+ Ok(result.into_inner())
125
+ }
126
+
127
+ async fn display_graph_structure( &self, query: String, branch: u64, frame: u64, ) -> anyhow::Result<String> {
128
+ let file_id = self.file_id.clone();
129
+ let url = self.url.clone();
130
+ let mut client = get_client(url).await?;
131
+ let file = client.current_file_state(RequestOnlyId {
132
+ id: file_id,
133
+ branch
134
+ }).await?;
135
+ let mut file = file.into_inner();
136
+ let mut g = CleanedDefinitionGraph::zero();
137
+ g.merge_file(&mut file).unwrap();
138
+ Ok(g.get_dot_graph())
139
+ }
140
+
141
+ async fn list_registered_graphs(&self) -> anyhow::Result<()> {
142
+ let file_id = self.file_id.clone();
143
+ let url = self.url.clone();
144
+ let mut client = get_client(url).await?;
145
+ let resp = client.list_registered_graphs(Empty { }).await?;
146
+ let mut stream = resp.into_inner();
147
+ while let Some(x) = stream.next().await {
148
+ // callback.call(py, (x,), None);
149
+ info!("Registered Graph = {:?}", x);
150
+ };
151
+ Ok(())
152
+ }
153
+
154
+ //
155
+ // // TODO: need to figure out how to handle callbacks
156
+ // // fn list_input_proposals<'a>(
157
+ // // mut self_: PyRefMut<'_, Self>,
158
+ // // py: Python<'a>,
159
+ // // callback: PyObject
160
+ // // ) -> PyResult<&'a PyAny> {
161
+ // // let file_id = self_.file_id.clone();
162
+ // // let url = self_.url.clone();
163
+ // // let branch = self_.current_branch;
164
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
165
+ // // let mut client = get_client(url).await?;
166
+ // // let resp = client.list_input_proposals(RequestOnlyId {
167
+ // // id: file_id,
168
+ // // branch,
169
+ // // }).await.map_err(PyErrWrapper::from)?;
170
+ // // let mut stream = resp.into_inner();
171
+ // // while let Some(x) = stream.next().await {
172
+ // // // callback.call(py, (x,), None);
173
+ // // info!("InputProposals = {:?}", x);
174
+ // // };
175
+ // // Ok(())
176
+ // // })
177
+ // // }
178
+ //
179
+ // // fn respond_to_input_proposal(mut self_: PyRefMut<'_, Self>) -> PyResult<()> {
180
+ // // Ok(())
181
+ // // }
182
+ //
183
+ // // TODO: need to figure out how to handle callbacks
184
+ // // fn list_change_events<'a>(
185
+ // // mut self_: PyRefMut<'_, Self>,
186
+ // // py: Python<'a>,
187
+ // // callback: PyObject
188
+ // // ) -> PyResult<&'a PyAny> {
189
+ // // let file_id = self_.file_id.clone();
190
+ // // let url = self_.url.clone();
191
+ // // let branch = self_.current_branch;
192
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
193
+ // // let mut client = get_client(url).await?;
194
+ // // let resp = client.list_change_events(RequestOnlyId {
195
+ // // id: file_id,
196
+ // // branch,
197
+ // // }).await.map_err(PyErrWrapper::from)?;
198
+ // // let mut stream = resp.into_inner();
199
+ // // while let Some(x) = stream.next().await {
200
+ // // Python::with_gil(|py| pyo3_asyncio::tokio::into_future(callback.as_ref(py).call((x.map(ChangeValueWithCounterWrapper).map_err(PyErrWrapper::from)?,), None)?))?
201
+ // // .await?;
202
+ // // };
203
+ // // Ok(())
204
+ // // })
205
+ // // }
206
+ //
207
+ //
208
+ //
209
+ // // TODO: this should accept an "Object" instead of args
210
+ // // TODO: nodes that are added should return a clean definition of what their addition looks like
211
+ // // TODO: adding a node should also display any errors
212
+
213
+
214
+ async fn poll_local_code_node_execution(&self) -> anyhow::Result<RespondPollNodeWillExecuteEvents> {
215
+ let file_id = self.file_id.clone();
216
+ let url = self.url.clone();
217
+ let mut client = get_client(url).await?;
218
+ let req = FilteredPollNodeWillExecuteEventsRequest { id: file_id.clone() };
219
+ let result = client.poll_node_will_execute_events(req).await?;
220
+ Ok(result.into_inner())
221
+ }
222
+
223
+ async fn ack_local_code_node_execution(&self, branch: u64, counter : u64) -> anyhow::Result<ExecutionStatus> {
224
+ let file_id = self.file_id.clone();
225
+ let url = self.url.clone();
226
+ let mut client = get_client(url).await?;
227
+ let result = client.ack_node_will_execute_event(RequestAckNodeWillExecuteEvent {
228
+ id: file_id.clone(),
229
+ branch,
230
+ counter,
231
+ }).await?;
232
+ Ok(result.into_inner())
233
+ }
234
+
235
+ async fn respond_local_code_node_execution(&self, branch: u64, counter: u64, node_name: String, response: Vec<ChangeValue>) -> anyhow::Result<ExecutionStatus> {
236
+ let file_id = self.file_id.clone();
237
+ let url = self.url.clone();
238
+
239
+ // TODO: need parent counters from the original change
240
+ // TODO: need source node
241
+ let mut client = get_client(url).await?;
242
+
243
+ // TODO: need to add the output table paths to these
244
+ // TODO: this needs to look more like a real change
245
+ Ok(client.push_worker_event(FileAddressedChangeValueWithCounter {
246
+ branch,
247
+ counter,
248
+ node_name,
249
+ id: file_id.clone(),
250
+ change: Some(ChangeValueWithCounter {
251
+ filled_values: response,
252
+ parent_monotonic_counters: vec![],
253
+ monotonic_counter: counter,
254
+ branch,
255
+ source_node: "".to_string(),
256
+ })
257
+ }).await?.into_inner())
258
+ }
23
259
  }
24
260
 
25
- #[macro_export]
26
- macro_rules! parameter {
27
- ($output_def:expr) => {
28
- create_node_parameter(
29
- format!("{}:{}", file!(), line!()),
30
- String::from($output_def)
31
- )
32
- };
33
- ($name:expr, $output_def:expr) => {
34
- create_node_parameter(
35
- String::from($name),
36
- String::from($output_def)
37
- )
38
- };
261
+
262
+ #[derive(serde::Serialize, serde::Deserialize)]
263
+ struct PromptNodeCreateOpts {
264
+ name: String,
265
+ queries: Option<Vec<String>>,
266
+ output_tables: Option<Vec<String>>,
267
+ template: String,
268
+ model: Option<String>
39
269
  }
40
270
 
41
- #[macro_export]
42
- macro_rules! map {
43
- ($query_def:expr, $path:expr) => {
44
- create_op_map(
45
- format!("{}:{}", file!(), line!()),
46
- String::from($query_def),
47
- String::from($path),
48
- )
49
- };
50
- ($name:expr, $query_def:expr, $path:expr) => {
51
- create_code_node(
52
- String::from($name),
53
- String::from($query_def),
54
- String::from($path),
55
- )
56
- };
271
+
272
+ #[derive(serde::Serialize, serde::Deserialize)]
273
+ struct CustomNodeCreateOpts {
274
+ name: String,
275
+ queries: Option<Vec<String>>,
276
+ output_tables: Option<Vec<String>>,
277
+ output: Option<String>,
278
+ node_type_name: String
57
279
  }
58
280
 
281
+ #[derive(serde::Serialize, serde::Deserialize)]
282
+ struct DenoCodeNodeCreateOpts {
283
+ name: String,
284
+ queries: Option<Vec<String>>,
285
+ output_tables: Option<Vec<String>>,
286
+ output: Option<String>,
287
+ code: String,
288
+ is_template: Option<bool>
289
+ }
59
290
 
60
- #[macro_export]
61
- macro_rules! code_node {
62
- ($query_def:expr, $output_def:expr, $source_type:expr) => {
63
- create_code_node(
64
- format!("{}:{}", file!(), line!()),
65
- String::from($query_def),
66
- String::from($output_def),
67
- $source_type,
68
- )
69
- };
70
- ($name:expr, $query_def:expr, $output_def:expr, $source_type:expr) => {
71
- create_code_node(
72
- String::from($name),
73
- String::from($query_def),
74
- String::from($output_def),
75
- String::from($source_type),
76
- )
77
- };
291
+ #[derive(serde::Serialize, serde::Deserialize)]
292
+ struct VectorMemoryNodeCreateOpts {
293
+ name: String,
294
+ queries: Option<Vec<String>>,
295
+ output_tables: Option<Vec<String>>,
296
+ output: Option<String>,
297
+ template: Option<String>, // TODO: default is the contents of the query
298
+ action: Option<String>, // TODO: default WRITE
299
+ embedding_model: Option<String>, // TODO: default TEXT_EMBEDDING_ADA_002
300
+ db_vendor: Option<String>, // TODO: default QDRANT
301
+ collection_name: String,
78
302
  }
79
303
 
80
304
 
81
- #[macro_export]
82
- macro_rules! observation_node {
83
- ($query_def:expr, $output_def:expr) => {
84
- create_observation_node(
85
- format!("{}:{}", file!(), line!()),
86
- String::from($query_def),
87
- String::from($output_def),
88
- )
89
- };
90
- ($name:expr, $query_def:expr, $output_def:expr) => {
91
- create_observation_node(
92
- String::from($name),
93
- String::from($query_def),
94
- String::from($output_def),
95
- )
305
+ fn remap_queries(queries: Option<Vec<String>>) -> Vec<Option<String>> {
306
+ let queries: Vec<Option<String>> = if let Some(queries) = queries {
307
+ queries.into_iter().map(|q| {
308
+ if q == "None".to_string() {
309
+ None
310
+ } else {
311
+ Some(q)
312
+ }
313
+ }).collect()
314
+ } else {
315
+ vec![]
96
316
  };
317
+ queries
97
318
  }
98
319
 
320
+ struct GraphBuilder {
321
+ clean_graph: CleanedDefinitionGraph,
322
+ }
99
323
 
100
- #[macro_export]
101
- macro_rules! memory_node {
102
- ($query_def:expr, $output_def:expr, $model:expr, $db:expr) => {
103
- create_vector_memory_node(
104
- format!("{}:{}", file!(), line!()),
105
- String::from($query_def),
106
- String::from($output_def),
107
- String::from($model),
108
- String::from($db)
109
- )
110
- };
111
- ($name:expr, $query_def:expr, $output_def:expr, $model:expr, $db:expr) => {
112
- create_vector_memory_node(
113
- String::from($name),
114
- String::from($query_def),
115
- String::from($output_def),
116
- String::from($model),
117
- String::from($db)
118
- )
119
- };
324
+ impl GraphBuilder {
325
+ fn prompt_node(&mut self, arg: PromptNodeCreateOpts) -> anyhow::Result<NodeHandle> {
326
+ let node = create_prompt_node(
327
+ arg.name,
328
+ remap_queries(arg.queries),
329
+ arg.template,
330
+ arg.model.unwrap_or("GPT_3_5_TURBO".to_string()),
331
+ arg.output_tables.unwrap_or(vec![]))?;
332
+ self.clean_graph.merge_file(&File { nodes: vec![node.clone()], ..Default::default() })?;
333
+ Ok(NodeHandle::from(node)?)
334
+ }
335
+
336
+ fn custom_node(&mut self, arg: CustomNodeCreateOpts) -> anyhow::Result<NodeHandle> {
337
+ let node = create_custom_node(
338
+ arg.name,
339
+ remap_queries(arg.queries.clone()),
340
+ arg.output.unwrap_or("type O {}".to_string()),
341
+ arg.node_type_name,
342
+ arg.output_tables.unwrap_or(vec![])
343
+ );
344
+ self.clean_graph.merge_file(&File { nodes: vec![node.clone()], ..Default::default() })?;
345
+ Ok(NodeHandle::from(node)?)
346
+ }
347
+
348
+
349
+ fn deno_code_node(&mut self, arg: DenoCodeNodeCreateOpts) -> anyhow::Result<NodeHandle> {
350
+ let node = create_code_node(
351
+ arg.name,
352
+ remap_queries(arg.queries.clone()),
353
+ arg.output.unwrap_or("type O {}".to_string()),
354
+ SourceNodeType::Code("DENO".to_string(), arg.code, arg.is_template.unwrap_or(false)),
355
+ arg.output_tables.unwrap_or(vec![])
356
+ );
357
+ self.clean_graph.merge_file(&File { nodes: vec![node.clone()], ..Default::default() })?;
358
+ Ok(NodeHandle::from(node)?)
359
+ }
360
+
361
+
362
+ fn vector_memory_node(&mut self, arg: VectorMemoryNodeCreateOpts) -> anyhow::Result<NodeHandle> {
363
+ let node = create_vector_memory_node(
364
+ arg.name,
365
+ remap_queries(arg.queries.clone()),
366
+ arg.output.unwrap_or("type O {}".to_string()),
367
+ arg.action.unwrap_or("READ".to_string()),
368
+ arg.embedding_model.unwrap_or("TEXT_EMBEDDING_ADA_002".to_string()),
369
+ arg.template.unwrap_or("".to_string()),
370
+ arg.db_vendor.unwrap_or("QDRANT".to_string()),
371
+ arg.collection_name,
372
+ arg.output_tables.unwrap_or(vec![])
373
+ )?;
374
+ self.clean_graph.merge_file(&File { nodes: vec![node.clone()], ..Default::default() })?;
375
+ Ok(NodeHandle::from(node)?)
376
+ }
377
+ //
378
+ //
379
+ // //
380
+ // // fn observation_node(mut self_: PyRefMut<'_, Self>, name: String, query_def: Option<String>, template: String, model: String) -> PyResult<()> {
381
+ // // let file_id = self_.file_id.clone();
382
+ // // let node = create_observation_node(
383
+ // // "".to_string(),
384
+ // // None,
385
+ // // "".to_string(),
386
+ // // );
387
+ // // executor::block_on(self_.client.merge(RequestFileMerge {
388
+ // // id: file_id,
389
+ // // file: Some(File {
390
+ // // nodes: vec![node],
391
+ // // ..Default::default()
392
+ // // }),
393
+ // // branch: 0,
394
+ // // }));
395
+ // // Ok(())
396
+ // // }
397
+
398
+ // // TODO: need to figure out passing a buffer of bytes
399
+ // // TODO: nodes that are added should return a clean definition of what their addition looks like
400
+ // // TODO: adding a node should also display any errors
401
+ // /// x = None
402
+ // /// with open("/Users/coltonpierson/Downloads/files_and_dirs.zip", "rb") as zip_file:
403
+ // /// contents = zip_file.read()
404
+ // /// x = await p.load_zip_file("LoadZip", """ output: String """, contents)
405
+ // /// x
406
+ // // #[pyo3(signature = (name=String::new(), output_tables=vec![], output=String::new(), bytes=vec![]))]
407
+ // // fn load_zip_file<'a>(
408
+ // // mut self_: PyRefMut<'_, Self>,
409
+ // // py: Python<'a>,
410
+ // // name: String,
411
+ // // output_tables: Vec<String>,
412
+ // // output: String,
413
+ // // bytes: Vec<u8>
414
+ // // ) -> PyResult<&'a PyAny> {
415
+ // // let file_id = self_.file_id.clone();
416
+ // // let url = self_.url.clone();
417
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
418
+ // // let node = create_loader_node(
419
+ // // name,
420
+ // // vec![],
421
+ // // output,
422
+ // // LoadFrom::ZipfileBytes(bytes),
423
+ // // output_tables
424
+ // // );
425
+ // // Ok(push_file_merge(&url, &file_id, node).await?)
426
+ // // })
427
+ // // }
428
+
429
+ async fn commit(&self, file_id: String, url: String, branch: u64) -> anyhow::Result<ExecutionStatus> {
430
+ let mut client = get_client(url.clone()).await?;
431
+ let nodes = self.clean_graph.node_by_name.clone().into_values().collect();
432
+ Ok(client.merge(RequestFileMerge {
433
+ id: file_id.clone(),
434
+ file: Some(File { nodes, ..Default::default() }),
435
+ branch: 0,
436
+ }).await.map(|x| x.into_inner())?)
437
+ }
120
438
  }
121
439
 
122
- #[macro_export]
123
- macro_rules! component_node {
124
- ($query_def:expr, $output_def:expr) => {
125
- create_component_node(
126
- format!("{}:{}", file!(), line!()),
127
- String::from($query_def),
128
- String::from($output_def),
129
- )
130
- };
131
- ($name:expr, $query_def:expr, $output_def:expr) => {
132
- create_component_node(
133
- String::from($name),
134
- String::from($query_def),
135
- String::from($output_def),
136
- )
137
- };
440
+
441
+ // Node handle
442
+ #[derive(Clone)]
443
+ pub struct NodeHandle {
444
+ node: Item,
445
+ indiv: CleanIndividualNode
138
446
  }
139
447
 
140
- #[macro_export]
141
- macro_rules! prompt_node {
142
- ($query_def:expr, $template:expr, $model:expr) => {
143
- create_prompt_node(
144
- format!("{}:{}", file!(), line!()),
145
- String::from($query_def),
146
- String::from($template),
147
- String::from($model),
148
- )
149
- };
150
- ($name:expr, $query_def:expr, $template:expr, $model:expr) => {
151
- create_prompt_node(
152
- String::from($name),
153
- String::from($query_def),
154
- String::from($template),
155
- String::from($model),
156
- )
157
- };
448
+ impl NodeHandle {
449
+ fn from(node: Item) -> anyhow::Result<NodeHandle> {
450
+ let indiv = derive_for_individual_node(&node)?;
451
+ Ok(NodeHandle {
452
+ node,
453
+ indiv
454
+ })
455
+ }
158
456
  }
159
457
 
160
- pub async fn run_worker(url: String, graph: DefinitionGraph) -> Result<()> {
161
- // validate the graph
162
- CleanedDefinitionGraph::new(&graph);
163
- let file_merge = RequestFileMerge{ file: Some(graph.get_file().clone()), branch: 0, id: "".to_string() };
164
- let mut client = ExecutionRuntimeClient::connect(url).await?;
165
- let _response = client.merge(file_merge).await?.into_inner();
166
- Ok(())
458
+
459
+ impl NodeHandle {
460
+ fn get_name(&self) -> String {
461
+ self.node.core.as_ref().unwrap().name.clone()
462
+ }
463
+
464
+ pub fn run_when(&mut self, other_node: &NodeHandle) -> anyhow::Result<bool> {
465
+ let queries = &mut self.node.core.as_mut().unwrap().queries;
466
+ let q = construct_query_from_output_type(
467
+ &other_node.get_name(),
468
+ &other_node.get_name(),
469
+ &self.indiv.output_path
470
+ ).unwrap();
471
+ queries.push(Query { query: Some(q)});
472
+ Ok(true)
473
+ }
474
+
475
+
476
+ pub async fn query(&self, file_id: String, url: String, branch: u64, frame: u64) -> anyhow::Result<HashMap<String, SerializedValue>> {
477
+ let name = &self.node.core.as_ref().unwrap().name;
478
+ let query = construct_query_from_output_type(&name, &name, &self.indiv.output_path).unwrap();
479
+ let mut client = get_client(url).await?;
480
+ let result = client.run_query(QueryAtFrame {
481
+ id: file_id,
482
+ query: Some(Query {
483
+ query: Some(query)
484
+ }),
485
+ frame,
486
+ branch,
487
+ }).await?;
488
+ let res = result.into_inner();
489
+ let mut obj = HashMap::new();
490
+ for value in res.values.iter() {
491
+ let c = value.change_value.as_ref().unwrap();
492
+ let k = c.path.as_ref().unwrap().address.join(":");
493
+ let v = c.value.as_ref().unwrap().clone();
494
+ obj.insert(k, v).unwrap();
495
+ }
496
+ Ok(obj)
497
+ }
498
+
167
499
  }
168
500
 
169
501
  #[cfg(test)]
170
502
  mod tests {
171
- use super::new_graph;
503
+ use super::*;
172
504
 
173
505
  #[test]
174
506
  fn test_new_graph() {
175
- new_graph();
176
507
  }
177
508
  }