@1kbirds/chidori 0.1.16

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.
@@ -0,0 +1,1239 @@
1
+ use std::cell::RefCell;
2
+ use std::collections::{HashMap, VecDeque};
3
+ use std::marker::PhantomData;
4
+ use anyhow::Error;
5
+ use futures::StreamExt;
6
+ use log::{debug, info};
7
+ use neon::{prelude::*, types::Deferred};
8
+ use neon::result::Throw;
9
+ use once_cell::sync::OnceCell;
10
+ use tokio::runtime::Runtime;
11
+ use prompt_graph_core::build_runtime_graph::graph_parse::{CleanedDefinitionGraph, CleanIndividualNode, construct_query_from_output_type, derive_for_individual_node};
12
+ use prompt_graph_core::graph_definition::{create_code_node, create_custom_node, create_prompt_node, create_vector_memory_node, SourceNodeType};
13
+ use prompt_graph_core::proto2::{ChangeValue, ChangeValueWithCounter, Empty, ExecutionStatus, File, FileAddressedChangeValueWithCounter, FilteredPollNodeWillExecuteEventsRequest, Item, ListBranchesRes, Path, Query, QueryAtFrame, QueryAtFrameResponse, RequestAckNodeWillExecuteEvent, RequestAtFrame, RequestFileMerge, RequestListBranches, RequestNewBranch, RequestOnlyId, SerializedValue, SerializedValueArray, SerializedValueObject};
14
+ use prompt_graph_core::proto2::execution_runtime_client::ExecutionRuntimeClient;
15
+ use prompt_graph_core::proto2::serialized_value::Val;
16
+ use prompt_graph_exec::tonic_runtime::run_server;
17
+ use neon_serde3;
18
+ use serde::{Deserialize, Serialize};
19
+
20
+ // Return a global tokio runtime or create one if it doesn't exist.
21
+ // Throws a JavaScript exception if the `Runtime` fails to create.
22
+ // TODO: note that oncecell has been recently stablized in rust stdlib, so we can probably use that instead
23
+ fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
24
+ static RUNTIME: OnceCell<Runtime> = OnceCell::new();
25
+ RUNTIME.get_or_try_init(|| Runtime::new().or_else(|err| cx.throw_error(err.to_string())))
26
+ }
27
+
28
+
29
+ async fn get_client(url: String) -> Result<ExecutionRuntimeClient<tonic::transport::Channel>, tonic::transport::Error> {
30
+ ExecutionRuntimeClient::connect(url.clone()).await
31
+ }
32
+
33
+
34
+ async fn push_file_merge(url: &String, file_id: &String, node: Item) -> anyhow::Result<NodeHandle> {
35
+ let mut client = get_client(url.clone()).await?;
36
+ let exec_status = client.merge(RequestFileMerge {
37
+ id: file_id.clone(),
38
+ file: Some(File {
39
+ nodes: vec![node.clone()],
40
+ ..Default::default()
41
+ }),
42
+ branch: 0,
43
+ }).await?.into_inner();
44
+ Ok(NodeHandle::from(
45
+ url.clone(),
46
+ file_id.clone(),
47
+ node,
48
+ exec_status
49
+ )?)
50
+ }
51
+
52
+
53
+ #[derive(Debug)]
54
+ pub struct SerializedValueWrapper(SerializedValue);
55
+
56
+ impl SerializedValueWrapper {
57
+ fn to_object<'a, T>(&self, cx: &mut T) -> JsResult<'a, JsValue> where
58
+ T: Context<'a> {
59
+ if let None = self.0.val {
60
+ let x: Option<bool> = None;
61
+ return Ok(cx.undefined().upcast());
62
+ }
63
+ let result: Handle<JsValue> = match self.0.val.as_ref().unwrap() {
64
+ Val::Float(x) => { cx.number(*x as f64).upcast() }
65
+ Val::Number(x) => { cx.number(*x as f64).upcast() }
66
+ Val::String(x) => { cx.string(x).upcast() }
67
+ Val::Boolean(x) => { cx.boolean(*x).upcast() }
68
+ Val::Array(val) => {
69
+ let mut js_list = cx.empty_array();
70
+ for (idx, item) in val.values.iter().enumerate() {
71
+ let js = SerializedValueWrapper(item.clone()).to_object(cx);
72
+ js_list.set(cx, idx as u32, js?)?;
73
+ }
74
+ js_list.upcast()
75
+ }
76
+ Val::Object(val) => {
77
+ let mut js_obj = cx.empty_object();
78
+ for (key, value) in &val.values {
79
+ let js = SerializedValueWrapper(value.clone()).to_object(cx);
80
+ js_obj.set(cx, key.as_str(), js?).unwrap();
81
+ }
82
+ js_obj.upcast()
83
+ }
84
+ };
85
+ Ok(result)
86
+ }
87
+ }
88
+
89
+
90
+ fn from_js_value<'a, C: Context<'a>>(cx: &mut C, value: Handle<JsValue>) -> NeonResult<SerializedValue> {
91
+ if value.is_a::<JsUndefined, _>(cx) {
92
+ return Ok(SerializedValue { val: None });
93
+ } else if let Ok(num) = value.downcast::<JsNumber, _>(cx) {
94
+ return Ok(SerializedValue { val: Some(Val::Float(num.value(cx) as f32))});
95
+ } else if let Ok(bool) = value.downcast::<JsBoolean, _>(cx) {
96
+ return Ok(SerializedValue { val: Some(Val::Boolean(bool.value(cx)))});
97
+ } else if let Ok(str) = value.downcast::<JsString, _>(cx) {
98
+ return Ok(SerializedValue { val: Some(Val::String(str.value(cx)))});
99
+ } else if let Ok(arr) = value.downcast::<JsArray, _>(cx) {
100
+ let mut vals = Vec::new();
101
+ for i in 0..arr.len(cx) {
102
+ let v = arr.get(cx, i)?;
103
+ vals.push(from_js_value(cx, v)?);
104
+ }
105
+ return Ok(SerializedValue { val: Some(Val::Array(SerializedValueArray { values: vals }))});
106
+ } else if let Ok(obj) = value.downcast::<JsObject, _>(cx) {
107
+ let mut vals = HashMap::new();
108
+ for key in obj.get_own_property_names(cx)?.to_vec(cx)? {
109
+ let v = obj.get(cx, key)?;
110
+ let k = key.downcast::<JsString, _>(cx);
111
+ vals.insert(k.unwrap().value(cx), from_js_value(cx, v)?);
112
+ }
113
+ return Ok(SerializedValue { val: Some(Val::Object(SerializedValueObject { values: vals }))});
114
+ }
115
+
116
+ cx.throw_error("Unsupported type")
117
+ }
118
+
119
+
120
+ // Node handle
121
+ #[derive(Clone)]
122
+ pub struct NodeHandle {
123
+ url: String,
124
+ file_id: String,
125
+ node: Item,
126
+ exec_status: ExecutionStatus,
127
+ indiv: CleanIndividualNode
128
+ }
129
+
130
+ impl NodeHandle {
131
+ fn example() -> Self{
132
+ let node = create_code_node(
133
+ "Example".to_string(),
134
+ vec![None],
135
+ "type O { output: String }".to_string(),
136
+ SourceNodeType::Code("DENO".to_string(), r#"return {"output": "hello"}"#.to_string(), false),
137
+ vec![],
138
+ );
139
+ let indiv = derive_for_individual_node(&node).unwrap();
140
+ NodeHandle {
141
+ url: "localhost:9800".to_string(),
142
+ file_id: "0".to_string(),
143
+ node: node,
144
+ exec_status: Default::default(),
145
+ indiv,
146
+ }
147
+ }
148
+
149
+ fn from(url: String, file_id: String, node: Item, exec_status: ExecutionStatus) -> anyhow::Result<NodeHandle> {
150
+ let indiv = derive_for_individual_node(&node)?;
151
+ Ok(NodeHandle {
152
+ url,
153
+ file_id,
154
+ node,
155
+ exec_status,
156
+ indiv
157
+ })
158
+ }
159
+ }
160
+
161
+ impl Finalize for NodeHandle {}
162
+
163
+
164
+ impl NodeHandle {
165
+ pub fn js_debug_example(mut cx: FunctionContext) -> JsResult<JsBox<RefCell<NodeHandle>>> {
166
+ let nh = NodeHandle::example();
167
+ Ok(cx.boxed(RefCell::new(nh)))
168
+ }
169
+
170
+ fn get_name(&self) -> String {
171
+ self.node.core.as_ref().unwrap().name.clone()
172
+ }
173
+
174
+ pub fn run_when(mut cx: FunctionContext) -> JsResult<JsPromise> {
175
+ let channel = cx.channel();
176
+ let (deferred, promise) = cx.promise();
177
+ let other_node = cx.argument::<JsBox<RefCell<NodeHandle>>>(0)?.downcast_or_throw::<JsBox<RefCell<NodeHandle>>, _>(&mut cx)?;
178
+
179
+ let self_ = cx.this()
180
+ .downcast_or_throw::<JsBox<RefCell<NodeHandle>>, _>(&mut cx)?;
181
+
182
+ let mut self_borrow = self_.borrow_mut();
183
+ let queries = &mut self_borrow.node.core.as_mut().unwrap().queries;
184
+
185
+ // Get the constructed query from the target node
186
+ let q = construct_query_from_output_type(
187
+ &other_node.borrow().get_name(),
188
+ &other_node.borrow().get_name(),
189
+ &self_.borrow().indiv.output_path
190
+ ).unwrap();
191
+
192
+ queries.push(Query { query: Some(q)});
193
+
194
+ let url = self_.borrow().url.clone();
195
+ let file_id = self_.borrow().file_id.clone();
196
+ let node = self_.borrow().node.clone();
197
+ let rt = runtime(&mut cx)?;
198
+ rt.spawn(async move {
199
+ let result = push_file_merge(&url, &file_id, node).await.unwrap();
200
+ deferred.settle_with(&channel, move |mut cx| {
201
+ Ok(cx.boolean(true))
202
+ });
203
+ });
204
+ Ok(promise)
205
+ }
206
+
207
+
208
+ pub fn query(mut cx: FunctionContext) -> JsResult<JsPromise> {
209
+ let (deferred, promise) = cx.promise();
210
+ let channel = cx.channel();
211
+
212
+ let branch = cx.argument::<JsNumber>(0)?.value(&mut cx) as u64;
213
+ let frame = cx.argument::<JsNumber>(1)?.value(&mut cx) as u64;
214
+
215
+ let self_ = cx.this()
216
+ .downcast_or_throw::<JsBox<RefCell<NodeHandle>>, _>(&mut cx)?;
217
+ let mut self_borrow = self_.borrow();
218
+ let file_id = self_borrow.file_id.clone();
219
+ let url = self_borrow.url.clone();
220
+ let name = &self_borrow.node.core.as_ref().unwrap().name;
221
+
222
+ let query = construct_query_from_output_type(&name, &name, &self_.borrow().indiv.output_path).unwrap();
223
+
224
+ let rt = runtime(&mut cx)?;
225
+ rt.spawn(async move {
226
+ let mut client = if let Ok(mut client) = get_client(url).await {
227
+ client
228
+ } else {
229
+ deferred.settle_with(&channel, move |mut cx| {
230
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
231
+ Ok(cx.undefined())
232
+ });
233
+ panic!("Failed to connect to runtime service.");
234
+ };
235
+ let result = client.run_query(QueryAtFrame {
236
+ id: file_id,
237
+ query: Some(Query {
238
+ query: Some(query)
239
+ }),
240
+ frame,
241
+ branch,
242
+ }).await;
243
+ deferred.settle_with(&channel, move |mut cx| {
244
+ if let Ok(result) = result {
245
+ let res = result.into_inner();
246
+ let mut obj = cx.empty_object();
247
+ for value in res.values.iter() {
248
+ let c = value.change_value.as_ref().unwrap();
249
+ let k = c.path.as_ref().unwrap().address.join(":");
250
+ let v = c.value.as_ref().unwrap().clone();
251
+ let js = SerializedValueWrapper(v).to_object(&mut cx);
252
+ obj.set(&mut cx, k.as_str(), js?).unwrap();
253
+ }
254
+ Ok(obj)
255
+ } else {
256
+ cx.throw_error("Failed to query")
257
+ }
258
+ });
259
+ });
260
+ Ok(promise)
261
+ }
262
+
263
+
264
+ // fn js_to_string(mut cx: FunctionContext) -> JsResult<JsUndefined> {
265
+ // let branch = cx.argument::<JsString>(0)?.value(&mut cx);
266
+ // let frame = cx.argument::<JsString>(1)?.value(&mut cx);
267
+ //
268
+ // let channel = cx.channel();
269
+ //
270
+ // // let name = self.get_name();
271
+ // Ok(format!("NodeHandle(file_id={}, node={})", self.file_id, name))
272
+ // //
273
+ // // Ok(cx.undefined())
274
+ // }
275
+ }
276
+
277
+
278
+
279
+ fn obj_to_paths<'a, C: Context<'a>>(cx: &mut C, d: Handle<JsObject>) -> NeonResult<Vec<(Vec<String>, SerializedValue)>> {
280
+ let mut paths = vec![];
281
+ let mut queue: VecDeque<(Vec<String>, Handle<JsObject>)> = VecDeque::new();
282
+ queue.push_back((Vec::new(), d));
283
+
284
+ while let Some((mut path, dict)) = queue.pop_front() {
285
+ let keys = dict.get_own_property_names(cx)?;
286
+ let len = keys.len(cx);
287
+
288
+ for i in 0..len {
289
+ let key = keys.get::<JsArray, _, u32>(cx, i).unwrap().downcast::<JsString, _>(cx).unwrap().value(cx);
290
+ path.push(key.clone());
291
+
292
+ let val: Handle<JsValue> = dict.get(cx, key.as_str())?;
293
+ if val.is_a::<JsObject, _>(cx) {
294
+ let sub_dict = val.downcast::<JsObject, _>(cx).unwrap();
295
+ queue.push_back((path.clone(), sub_dict));
296
+ } else {
297
+ let v = from_js_value(cx, val)?;
298
+ paths.push((path.clone(), v));
299
+ }
300
+
301
+ path.pop();
302
+ }
303
+ }
304
+
305
+ Ok(paths)
306
+ }
307
+
308
+
309
+
310
+
311
+ #[derive(serde::Serialize, serde::Deserialize)]
312
+ struct PromptNodeCreateOpts {
313
+ name: String,
314
+ queries: Option<Vec<String>>,
315
+ output_tables: Option<Vec<String>>,
316
+ template: String,
317
+ model: Option<String>
318
+ }
319
+
320
+
321
+ #[derive(serde::Serialize, serde::Deserialize)]
322
+ struct CustomNodeCreateOpts {
323
+ name: String,
324
+ queries: Option<Vec<String>>,
325
+ output_tables: Option<Vec<String>>,
326
+ output: Option<String>,
327
+ node_type_name: String
328
+ }
329
+
330
+ #[derive(serde::Serialize, serde::Deserialize)]
331
+ struct DenoCodeNodeCreateOpts {
332
+ name: String,
333
+ queries: Option<Vec<String>>,
334
+ output_tables: Option<Vec<String>>,
335
+ output: Option<String>,
336
+ code: String,
337
+ is_template: Option<bool>
338
+ }
339
+
340
+ #[derive(serde::Serialize, serde::Deserialize)]
341
+ struct VectorMemoryNodeCreateOpts {
342
+ name: String,
343
+ queries: Option<Vec<String>>,
344
+ output_tables: Option<Vec<String>>,
345
+ output: Option<String>,
346
+ template: Option<String>, // TODO: default is the contents of the query
347
+ action: Option<String>, // TODO: default WRITE
348
+ embedding_model: Option<String>, // TODO: default TEXT_EMBEDDING_ADA_002
349
+ db_vendor: Option<String>, // TODO: default QDRANT
350
+ collection_name: String,
351
+ }
352
+
353
+
354
+ struct Chidori {
355
+ file_id: String,
356
+ current_head: u64,
357
+ current_branch: u64,
358
+ url: String
359
+ }
360
+
361
+ impl Finalize for Chidori {}
362
+
363
+ impl Chidori {
364
+
365
+ fn js_new(mut cx: FunctionContext) -> JsResult<JsBox<Chidori>> {
366
+ let file_id = cx.argument::<JsString>(0)?.value(&mut cx);
367
+ let url = cx.argument::<JsString>(1)?.value(&mut cx);
368
+
369
+ if !url.contains("://") {
370
+ return cx.throw_error("Invalid url, must include protocol");
371
+ }
372
+ // let api_token = cx.argument_opt(2)?.value(&mut cx);
373
+ debug!("Creating new Chidori instance with file_id={}, url={}, api_token={:?}", file_id, url, "".to_string());
374
+ Ok(cx.boxed(Chidori {
375
+ file_id,
376
+ current_head: 0,
377
+ current_branch: 0,
378
+ url,
379
+ }))
380
+ }
381
+
382
+ fn start_server(mut cx: FunctionContext) -> JsResult<JsPromise> {
383
+ let channel = cx.channel();
384
+ let self_ = cx.this()
385
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
386
+ let (deferred, promise) = cx.promise();
387
+ let url_server = self_.url.clone();
388
+ let file_path: Option<String> = match cx.argument_opt(0) {
389
+ Some(v) => Some(v.downcast_or_throw(&mut cx)),
390
+ None => None,
391
+ }.map(|p: JsResult<JsString>| p.unwrap().value(&mut cx));
392
+ std::thread::spawn(move || {
393
+ let result = run_server(url_server, file_path);
394
+ match result {
395
+ Ok(_) => {
396
+ println!("Server exited");
397
+ },
398
+ Err(e) => {
399
+ println!("Error running server: {}", e);
400
+ },
401
+ }
402
+ });
403
+
404
+ let url = self_.url.clone();
405
+ let rt = runtime(&mut cx)?;
406
+ rt.spawn(async move {
407
+ 'retry: loop {
408
+ let client = get_client(url.clone());
409
+ match client.await {
410
+ Ok(connection) => {
411
+ eprintln!("Connection successfully established {:?}", &url);
412
+ deferred.settle_with(&channel, move |mut cx| {
413
+ Ok(cx.undefined())
414
+ });
415
+ break 'retry
416
+ },
417
+ Err(e) => {
418
+ eprintln!("Error connecting to server: {} with Error {}. Retrying...", &url, &e.to_string());
419
+ std::thread::sleep(std::time::Duration::from_millis(1000));
420
+ }
421
+ }
422
+ }
423
+ });
424
+ Ok(promise)
425
+ }
426
+
427
+ fn play(mut cx: FunctionContext) -> JsResult<JsPromise> {
428
+ let channel = cx.channel();
429
+ let (deferred, promise) = cx.promise();
430
+ let self_ = cx.this()
431
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
432
+ let branch = cx.argument::<JsNumber>(0).unwrap_or(JsNumber::new(&mut cx, 0.0)).value(&mut cx) as u64;
433
+ let frame = cx.argument::<JsNumber>(1).unwrap_or(JsNumber::new(&mut cx, 0.0)).value(&mut cx) as u64;
434
+
435
+ let file_id = self_.file_id.clone();
436
+ let url = self_.url.clone();
437
+
438
+ let rt = runtime(&mut cx)?;
439
+ rt.spawn(async move {
440
+ let mut client = if let Ok(mut client) = get_client(url).await {
441
+ client
442
+ } else {
443
+ deferred.settle_with(&channel, move |mut cx| {
444
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
445
+ Ok(cx.undefined())
446
+ });
447
+ panic!("Failed to connect to runtime service.");
448
+ };
449
+ let result = client.play(RequestAtFrame {
450
+ id: file_id,
451
+ frame,
452
+ branch,
453
+ }).await;
454
+ deferred.settle_with(&channel, move |mut cx| {
455
+ if let Ok(result) = result {
456
+ neon_serde3::to_value(&mut cx, &result.into_inner())
457
+ .or_else(|e| cx.throw_error(e.to_string()))
458
+ } else {
459
+ cx.throw_error("Failed to play runtime.")
460
+ }
461
+ });
462
+ });
463
+ Ok(promise)
464
+ }
465
+
466
+ fn pause(mut cx: FunctionContext) -> JsResult<JsPromise> {
467
+ let channel = cx.channel();
468
+ let (deferred, promise) = cx.promise();
469
+ let self_ = cx.this()
470
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
471
+ let frame = cx.argument::<JsNumber>(0).unwrap_or(JsNumber::new(&mut cx, 0.0)).value(&mut cx) as u64;
472
+ let file_id = self_.file_id.clone();
473
+ let url = self_.url.clone();
474
+ let branch = self_.current_branch.clone();
475
+
476
+ let rt = runtime(&mut cx)?;
477
+ rt.spawn(async move {
478
+ let mut client = if let Ok(mut client) = get_client(url).await {
479
+ client
480
+ } else {
481
+ deferred.settle_with(&channel, move |mut cx| {
482
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
483
+ Ok(cx.undefined())
484
+ });
485
+ panic!("Failed to connect to runtime service.");
486
+ };
487
+ let result = client.pause(RequestAtFrame {
488
+ id: file_id,
489
+ frame,
490
+ branch,
491
+ }).await;
492
+ deferred.settle_with(&channel, move |mut cx| {
493
+ if let Ok(result) = result {
494
+ neon_serde3::to_value(&mut cx, &result.into_inner())
495
+ .or_else(|e| cx.throw_error(e.to_string()))
496
+ } else {
497
+ cx.throw_error("Failed to play runtime.")
498
+ }
499
+ });
500
+ });
501
+ Ok(promise)
502
+ }
503
+
504
+ fn branch(mut cx: FunctionContext) -> JsResult<JsPromise> {
505
+ let channel = cx.channel();
506
+ let (deferred, promise) = cx.promise();
507
+ let self_ = cx.this()
508
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
509
+ let file_id = self_.file_id.clone();
510
+ let url = self_.url.clone();
511
+ let branch = self_.current_branch.clone();
512
+ let rt = runtime(&mut cx)?;
513
+ rt.spawn(async move {
514
+ let mut client = if let Ok(mut client) = get_client(url).await {
515
+ client
516
+ } else {
517
+ deferred.settle_with(&channel, move |mut cx| {
518
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
519
+ Ok(cx.undefined())
520
+ });
521
+ panic!("Failed to connect to runtime service.");
522
+ };
523
+ let result = client.branch(RequestNewBranch {
524
+ id: file_id,
525
+ source_branch_id: branch,
526
+ diverges_at_counter: 0,
527
+ }).await;
528
+ // TODO: need to somehow handle writing to the current_branch
529
+ deferred.settle_with(&channel, move |mut cx| {
530
+ if let Ok(result) = result {
531
+ neon_serde3::to_value(&mut cx, &result.into_inner())
532
+ .or_else(|e| cx.throw_error(e.to_string()))
533
+ } else {
534
+ cx.throw_error("Failed to play runtime.")
535
+ }
536
+ });
537
+ });
538
+ Ok(promise)
539
+ }
540
+
541
+ fn query(mut cx: FunctionContext) -> JsResult<JsPromise> {
542
+ let channel = cx.channel();
543
+ let (deferred, promise) = cx.promise();
544
+ let self_ = cx.this()
545
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
546
+ let query = cx.argument::<JsString>(0).unwrap_or(JsString::new(&mut cx, "")).value(&mut cx);
547
+ let branch = cx.argument::<JsNumber>(1).unwrap_or(JsNumber::new(&mut cx, 0.0)).value(&mut cx) as u64;
548
+ let frame = cx.argument::<JsNumber>(2).unwrap_or(JsNumber::new(&mut cx, 0.0)).value(&mut cx) as u64;
549
+ let file_id = self_.file_id.clone();
550
+ let url = self_.url.clone();
551
+ let rt = runtime(&mut cx)?;
552
+ rt.spawn(async move {
553
+ let mut client = if let Ok(mut client) = get_client(url).await {
554
+ client
555
+ } else {
556
+ deferred.settle_with(&channel, move |mut cx| {
557
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
558
+ Ok(cx.undefined())
559
+ });
560
+ panic!("Failed to connect to runtime service.");
561
+ };
562
+ let result = client.run_query(QueryAtFrame {
563
+ id: file_id,
564
+ query: Some(Query {
565
+ query: Some(query)
566
+ }),
567
+ frame,
568
+ branch,
569
+ }).await;
570
+ deferred.settle_with(&channel, move |mut cx| {
571
+ if let Ok(result) = result {
572
+ neon_serde3::to_value(&mut cx, &result.into_inner())
573
+ .or_else(|e| cx.throw_error(e.to_string()))
574
+ } else {
575
+ cx.throw_error("Failed to play runtime.")
576
+ }
577
+ });
578
+ });
579
+ Ok(promise)
580
+ }
581
+
582
+ fn list_branches(mut cx: FunctionContext) -> JsResult<JsPromise> {
583
+ let channel = cx.channel();
584
+ let (deferred, promise) = cx.promise();
585
+ let self_ = cx.this()
586
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
587
+ let file_id = self_.file_id.clone();
588
+ let url = self_.url.clone();
589
+ let rt = runtime(&mut cx)?;
590
+ rt.spawn(async move {
591
+ let mut client = if let Ok(mut client) = get_client(url).await {
592
+ client
593
+ } else {
594
+ deferred.settle_with(&channel, move |mut cx| {
595
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
596
+ Ok(cx.undefined())
597
+ });
598
+ panic!("Failed to connect to runtime service.");
599
+ };
600
+ let result = client.list_branches(RequestListBranches {
601
+ id: file_id,
602
+ }).await;
603
+ deferred.settle_with(&channel, move |mut cx| {
604
+ if let Ok(result) = result {
605
+ neon_serde3::to_value(&mut cx, &result.into_inner())
606
+ .or_else(|e| cx.throw_error(e.to_string()))
607
+ } else {
608
+ cx.throw_error("Failed to play runtime.")
609
+ }
610
+ });
611
+ });
612
+ Ok(promise)
613
+ }
614
+
615
+ fn display_graph_structure(mut cx: FunctionContext) -> JsResult<JsPromise> {
616
+ let channel = cx.channel();
617
+ let (deferred, promise) = cx.promise();
618
+ let self_ = cx.this()
619
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
620
+ let file_id = self_.file_id.clone();
621
+ let url = self_.url.clone();
622
+ let branch = self_.current_branch.clone();
623
+ let rt = runtime(&mut cx)?;
624
+ rt.spawn(async move {
625
+ let mut client = if let Ok(mut client) = get_client(url).await {
626
+ client
627
+ } else {
628
+ deferred.settle_with(&channel, move |mut cx| {
629
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
630
+ Ok(cx.undefined())
631
+ });
632
+ panic!("Failed to connect to runtime service.");
633
+ };
634
+ let file = if let Ok(file) = client.current_file_state(RequestOnlyId {
635
+ id: file_id,
636
+ branch
637
+ }).await {
638
+ file
639
+ } else {
640
+ deferred.settle_with(&channel, move |mut cx| {
641
+ cx.throw_error::<&str, JsUndefined>("Failed to get current file state.");
642
+ Ok(cx.undefined())
643
+ });
644
+ panic!("Failed to get current file state.");
645
+ };
646
+ let mut file = file.into_inner();
647
+ let mut g = CleanedDefinitionGraph::zero();
648
+ g.merge_file(&mut file).unwrap();
649
+ deferred.settle_with(&channel, move |mut cx| {
650
+ Ok(cx.string(g.get_dot_graph()))
651
+ });
652
+ });
653
+ Ok(promise)
654
+ }
655
+
656
+ //
657
+ // // TODO: some of these register handlers instead
658
+ // // TODO: list registered graphs should not stream
659
+ // // TODO: add a message that sends the current graph state
660
+ //
661
+
662
+ fn list_registered_graphs(mut cx: FunctionContext) -> JsResult<JsPromise> {
663
+ let channel = cx.channel();
664
+ let (deferred, promise) = cx.promise();
665
+ let self_ = cx.this()
666
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
667
+ let file_id = self_.file_id.clone();
668
+ let url = self_.url.clone();
669
+ let rt = runtime(&mut cx)?;
670
+ rt.spawn(async move {
671
+ let mut client = if let Ok(mut client) = get_client(url).await {
672
+ client
673
+ } else {
674
+ deferred.settle_with(&channel, move |mut cx| {
675
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
676
+ Ok(cx.undefined())
677
+ });
678
+ panic!("Failed to connect to runtime service.");
679
+ };
680
+ let resp = if let Ok(resp) = client.list_registered_graphs(Empty {
681
+ }).await {
682
+ resp
683
+ } else {
684
+ deferred.settle_with(&channel, move |mut cx| {
685
+ cx.throw_error::<&str, JsUndefined>("Failed to get registered graph stream.");
686
+ Ok(cx.undefined())
687
+ });
688
+ panic!("Failed to get registered graph stream.");
689
+ };
690
+ let mut stream = resp.into_inner();
691
+ while let Some(x) = stream.next().await {
692
+ // callback.call(py, (x,), None);
693
+ info!("Registered Graph = {:?}", x);
694
+ };
695
+ deferred.settle_with(&channel, move |mut cx| {
696
+ Ok(cx.undefined())
697
+ });
698
+ });
699
+ Ok(promise)
700
+ }
701
+
702
+ //
703
+ // // TODO: need to figure out how to handle callbacks
704
+ // // fn list_input_proposals<'a>(
705
+ // // mut self_: PyRefMut<'_, Self>,
706
+ // // py: Python<'a>,
707
+ // // callback: PyObject
708
+ // // ) -> PyResult<&'a PyAny> {
709
+ // // let file_id = self_.file_id.clone();
710
+ // // let url = self_.url.clone();
711
+ // // let branch = self_.current_branch;
712
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
713
+ // // let mut client = get_client(url).await?;
714
+ // // let resp = client.list_input_proposals(RequestOnlyId {
715
+ // // id: file_id,
716
+ // // branch,
717
+ // // }).await.map_err(PyErrWrapper::from)?;
718
+ // // let mut stream = resp.into_inner();
719
+ // // while let Some(x) = stream.next().await {
720
+ // // // callback.call(py, (x,), None);
721
+ // // info!("InputProposals = {:?}", x);
722
+ // // };
723
+ // // Ok(())
724
+ // // })
725
+ // // }
726
+ //
727
+ // // fn respond_to_input_proposal(mut self_: PyRefMut<'_, Self>) -> PyResult<()> {
728
+ // // Ok(())
729
+ // // }
730
+ //
731
+ // // TODO: need to figure out how to handle callbacks
732
+ // // fn list_change_events<'a>(
733
+ // // mut self_: PyRefMut<'_, Self>,
734
+ // // py: Python<'a>,
735
+ // // callback: PyObject
736
+ // // ) -> PyResult<&'a PyAny> {
737
+ // // let file_id = self_.file_id.clone();
738
+ // // let url = self_.url.clone();
739
+ // // let branch = self_.current_branch;
740
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
741
+ // // let mut client = get_client(url).await?;
742
+ // // let resp = client.list_change_events(RequestOnlyId {
743
+ // // id: file_id,
744
+ // // branch,
745
+ // // }).await.map_err(PyErrWrapper::from)?;
746
+ // // let mut stream = resp.into_inner();
747
+ // // while let Some(x) = stream.next().await {
748
+ // // Python::with_gil(|py| pyo3_asyncio::tokio::into_future(callback.as_ref(py).call((x.map(ChangeValueWithCounterWrapper).map_err(PyErrWrapper::from)?,), None)?))?
749
+ // // .await?;
750
+ // // };
751
+ // // Ok(())
752
+ // // })
753
+ // // }
754
+ //
755
+ //
756
+ // // TODO: need to figure out passing a buffer of bytes
757
+ // // TODO: nodes that are added should return a clean definition of what their addition looks like
758
+ // // TODO: adding a node should also display any errors
759
+ // /// x = None
760
+ // /// with open("/Users/coltonpierson/Downloads/files_and_dirs.zip", "rb") as zip_file:
761
+ // /// contents = zip_file.read()
762
+ // /// x = await p.load_zip_file("LoadZip", """ output: String """, contents)
763
+ // /// x
764
+ // // #[pyo3(signature = (name=String::new(), output_tables=vec![], output=String::new(), bytes=vec![]))]
765
+ // // fn load_zip_file<'a>(
766
+ // // mut self_: PyRefMut<'_, Self>,
767
+ // // py: Python<'a>,
768
+ // // name: String,
769
+ // // output_tables: Vec<String>,
770
+ // // output: String,
771
+ // // bytes: Vec<u8>
772
+ // // ) -> PyResult<&'a PyAny> {
773
+ // // let file_id = self_.file_id.clone();
774
+ // // let url = self_.url.clone();
775
+ // // pyo3_asyncio::tokio::future_into_py(py, async move {
776
+ // // let node = create_loader_node(
777
+ // // name,
778
+ // // vec![],
779
+ // // output,
780
+ // // LoadFrom::ZipfileBytes(bytes),
781
+ // // output_tables
782
+ // // );
783
+ // // Ok(push_file_merge(&url, &file_id, node).await?)
784
+ // // })
785
+ // // }
786
+ //
787
+ // // TODO: this should accept an "Object" instead of args
788
+ // // TODO: nodes that are added should return a clean definition of what their addition looks like
789
+ // // TODO: adding a node should also display any errors
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
+
806
+ fn prompt_node(mut cx: FunctionContext) -> JsResult<JsPromise> {
807
+ let channel = cx.channel();
808
+ let (deferred, promise) = cx.promise();
809
+ let self_ = cx.this()
810
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
811
+
812
+ let arg0 = cx.argument::<JsValue>(0)?;
813
+ let arg0_value: PromptNodeCreateOpts = match neon_serde3::from_value(&mut cx, arg0) {
814
+ Ok(value) => value,
815
+ Err(e) => {
816
+ return cx.throw_error(e.to_string());
817
+ }
818
+ };
819
+
820
+ let queries: Vec<Option<String>> = if let Some(queries) = arg0_value.queries {
821
+ queries.into_iter().map(|q| {
822
+ if q == "None".to_string() {
823
+ None
824
+ } else {
825
+ Some(q)
826
+ }
827
+ }).collect()
828
+ } else {
829
+ vec![None]
830
+ };
831
+
832
+ let file_id = self_.file_id.clone();
833
+ let url = self_.url.clone();
834
+ let rt = runtime(&mut cx)?;
835
+ rt.spawn(async move {
836
+ let prompt_node = create_prompt_node(
837
+ arg0_value.name,
838
+ queries,
839
+ arg0_value.template,
840
+ arg0_value.model.unwrap_or("GPT_3_5_TURBO".to_string()),
841
+ arg0_value.output_tables.unwrap_or(vec![]));
842
+ let node = if let Ok(node) = prompt_node {
843
+ node
844
+ } else {
845
+ deferred.settle_with(&channel, move |mut cx| {
846
+ // TODO: throw error
847
+ Ok(cx.undefined())
848
+ });
849
+ panic!("Failed to connect to runtime service.");
850
+ };
851
+
852
+ if let Ok(result ) = push_file_merge(&url, &file_id, node).await {
853
+ deferred.settle_with(&channel, move |mut cx| {
854
+ Ok(cx.boxed(RefCell::new(result)))
855
+ });
856
+ } else {
857
+ deferred.settle_with(&channel, move |mut cx| {
858
+ // TODO: throw error
859
+ Ok(cx.undefined())
860
+ });
861
+ panic!("Failed to connect to runtime service.");
862
+ };
863
+ });
864
+ Ok(promise)
865
+ }
866
+
867
+
868
+ fn poll_local_code_node_execution(mut cx: FunctionContext) -> JsResult<JsPromise> {
869
+ let channel = cx.channel();
870
+ let (deferred, promise) = cx.promise();
871
+ let self_ = cx.this()
872
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
873
+ let file_id = self_.file_id.clone();
874
+ let url = self_.url.clone();
875
+
876
+ let rt = runtime(&mut cx)?;
877
+ rt.spawn(async move {
878
+ let mut client = if let Ok(mut client) = get_client(url).await {
879
+ client
880
+ } else {
881
+ deferred.settle_with(&channel, move |mut cx| {
882
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
883
+ Ok(cx.undefined())
884
+ });
885
+ panic!("Failed to connect to runtime service.");
886
+ };
887
+ if let Ok(result) = client.poll_node_will_execute_events(FilteredPollNodeWillExecuteEventsRequest {
888
+ id: file_id.clone(),
889
+ }).await {
890
+ debug!("poll_local_code_node_execution result = {:?}", result);
891
+ deferred.settle_with(&channel, move |mut cx| {
892
+ neon_serde3::to_value(&mut cx, &result.into_inner())
893
+ .or_else(|e| cx.throw_error(e.to_string()))
894
+ });
895
+ } else {
896
+ deferred.settle_with(&channel, move |mut cx| {
897
+ // TODO: throw error
898
+ Ok(cx.undefined())
899
+ });
900
+ };
901
+ });
902
+ Ok(promise)
903
+ }
904
+ fn ack_local_code_node_execution(mut cx: FunctionContext) -> JsResult<JsPromise> {
905
+ let channel = cx.channel();
906
+ let (deferred, promise) = cx.promise();
907
+ let self_ = cx.this()
908
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
909
+ let file_id = self_.file_id.clone();
910
+ let url = self_.url.clone();
911
+ let branch = cx.argument::<JsNumber>(0)?.value(&mut cx) as u64;
912
+ let counter = cx.argument::<JsNumber>(1)?.value(&mut cx) as u64;
913
+ let rt = runtime(&mut cx)?;
914
+ rt.spawn(async move {
915
+ let mut client = if let Ok(mut client) = get_client(url).await {
916
+ client
917
+ } else {
918
+ deferred.settle_with(&channel, move |mut cx| {
919
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
920
+ Ok(cx.undefined())
921
+ });
922
+ panic!("Failed to connect to runtime service.");
923
+ };
924
+ if let Ok(result) = client.ack_node_will_execute_event(RequestAckNodeWillExecuteEvent {
925
+ id: file_id.clone(),
926
+ branch,
927
+ counter,
928
+ }).await {
929
+ deferred.settle_with(&channel, move |mut cx| {
930
+ neon_serde3::to_value(&mut cx, &result.into_inner())
931
+ .or_else(|e| cx.throw_error(e.to_string()))
932
+ });
933
+ } else {
934
+ deferred.settle_with(&channel, move |mut cx| {
935
+ // TODO: throw error
936
+ Ok(cx.undefined())
937
+ });
938
+ }
939
+ });
940
+ Ok(promise)
941
+ }
942
+
943
+ fn respond_local_code_node_execution(mut cx: FunctionContext) -> JsResult<JsPromise> {
944
+ let channel = cx.channel();
945
+ let (deferred, promise) = cx.promise();
946
+ let self_ = cx.this()
947
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
948
+ let file_id = self_.file_id.clone();
949
+ let url = self_.url.clone();
950
+
951
+ let branch = cx.argument::<JsNumber>(0)?.value(&mut cx) as u64;
952
+ let counter = cx.argument::<JsNumber>(1)?.value(&mut cx) as u64;
953
+ let node_name = cx.argument::<JsString>(2)?.value(&mut cx);
954
+
955
+ let response: Option<JsResult<JsObject>> = match cx.argument_opt(0) {
956
+ Some(v) => Some(v.downcast_or_throw(&mut cx)),
957
+ None => None,
958
+ };
959
+
960
+ // TODO: need parent counters from the original change
961
+ // TODO: need source node
962
+
963
+ let response_paths = if let Some(response) = response {
964
+ // TODO: need better error handling here
965
+ obj_to_paths(&mut cx, response.unwrap()).unwrap()
966
+ } else {
967
+ vec![]
968
+ };
969
+
970
+ let rt = runtime(&mut cx)?;
971
+ rt.spawn(async move {
972
+ let mut client = if let Ok(mut client) = get_client(url).await {
973
+ client
974
+ } else {
975
+ deferred.settle_with(&channel, move |mut cx| {
976
+ cx.throw_error::<&str, JsUndefined>("Failed to connect to runtime service.");
977
+ Ok(cx.undefined())
978
+ });
979
+ panic!("Failed to connect to runtime service.");
980
+ };
981
+
982
+ // TODO: need to add the output table paths to these
983
+ let filled_values = response_paths.into_iter().map(|path| {
984
+ ChangeValue {
985
+ path: Some(Path {
986
+ address: path.0,
987
+ }),
988
+ value: Some(path.1),
989
+ branch,
990
+ }
991
+ });
992
+
993
+ // TODO: this needs to look more like a real change
994
+ client.push_worker_event(FileAddressedChangeValueWithCounter {
995
+ branch,
996
+ counter,
997
+ node_name,
998
+ id: file_id.clone(),
999
+ change: Some(ChangeValueWithCounter {
1000
+ filled_values: filled_values.collect(),
1001
+ parent_monotonic_counters: vec![],
1002
+ monotonic_counter: counter,
1003
+ branch,
1004
+ source_node: "".to_string(),
1005
+ })
1006
+ }).await.unwrap();
1007
+ });
1008
+ Ok(promise)
1009
+ }
1010
+
1011
+ // // }
1012
+ //
1013
+ // // TODO: handle dispatch to this handler - should accept a callback
1014
+ // // https://github.com/PyO3/pyo3/issues/525
1015
+ fn custom_node(mut cx: FunctionContext) -> JsResult<JsPromise> {
1016
+ let channel = cx.channel();
1017
+ let (deferred, promise) = cx.promise();
1018
+ let self_ = cx.this()
1019
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
1020
+
1021
+ let arg0 = cx.argument::<JsValue>(0)?;
1022
+ let arg0_value: CustomNodeCreateOpts = match neon_serde3::from_value(&mut cx, arg0) {
1023
+ Ok(value) => value,
1024
+ Err(e) => {
1025
+ return cx.throw_error(e.to_string());
1026
+ }
1027
+ };
1028
+
1029
+ let queries: Vec<Option<String>> = if let Some(queries) = arg0_value.queries {
1030
+ queries.into_iter().map(|q| {
1031
+ if q == "None".to_string() {
1032
+ None
1033
+ } else {
1034
+ Some(q)
1035
+ }
1036
+ }).collect()
1037
+ } else {
1038
+ vec![]
1039
+ };
1040
+
1041
+ let file_id = self_.file_id.clone();
1042
+ let url = self_.url.clone();
1043
+ let branch = self_.current_branch;
1044
+ let rt = runtime(&mut cx)?;
1045
+ rt.spawn(async move {
1046
+ // Register the node with the system
1047
+ let node = create_custom_node(
1048
+ arg0_value.name,
1049
+ queries,
1050
+ arg0_value.output.unwrap_or("type O {}".to_string()),
1051
+ arg0_value.node_type_name,
1052
+ arg0_value.output_tables.unwrap_or(vec![])
1053
+ );
1054
+ if let Ok(result ) = push_file_merge(&url, &file_id, node).await {
1055
+ deferred.settle_with(&channel, move |mut cx| {
1056
+ Ok(cx.boxed(RefCell::new(result)))
1057
+ });
1058
+ } else {
1059
+ deferred.settle_with(&channel, move |mut cx| {
1060
+ // TODO: throw error
1061
+ Ok(cx.undefined())
1062
+ });
1063
+ panic!("Failed to connect to runtime service.");
1064
+ };
1065
+ });
1066
+ Ok(promise)
1067
+ }
1068
+
1069
+ fn deno_code_node(mut cx: FunctionContext) -> JsResult<JsPromise> {
1070
+ let channel = cx.channel();
1071
+ let (deferred, promise) = cx.promise();
1072
+ let self_ = cx.this()
1073
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
1074
+
1075
+ let arg0 = cx.argument::<JsValue>(0)?;
1076
+ let arg0_value: DenoCodeNodeCreateOpts = match neon_serde3::from_value(&mut cx, arg0) {
1077
+ Ok(value) => value,
1078
+ Err(e) => {
1079
+ return cx.throw_error(e.to_string());
1080
+ }
1081
+ };
1082
+
1083
+ let queries: Vec<Option<String>> = if let Some(queries) = arg0_value.queries {
1084
+ queries.into_iter().map(|q| {
1085
+ if q == "None".to_string() {
1086
+ None
1087
+ } else {
1088
+ Some(q)
1089
+ }
1090
+ }).collect()
1091
+ } else {
1092
+ vec![None]
1093
+ };
1094
+
1095
+ let file_id = self_.file_id.clone();
1096
+ let url = self_.url.clone();
1097
+ let branch = self_.current_branch;
1098
+
1099
+ let rt = runtime(&mut cx)?;
1100
+ rt.spawn(async move {
1101
+ let node = create_code_node(
1102
+ arg0_value.name,
1103
+ queries,
1104
+ arg0_value.output.unwrap_or("type O {}".to_string()),
1105
+ SourceNodeType::Code("DENO".to_string(), arg0_value.code, arg0_value.is_template.unwrap_or(false)),
1106
+ arg0_value.output_tables.unwrap_or(vec![])
1107
+ );
1108
+ if let Ok(result ) = push_file_merge(&url, &file_id, node).await {
1109
+ deferred.settle_with(&channel, move |mut cx| {
1110
+ Ok(cx.boxed(RefCell::new(result)))
1111
+ });
1112
+ } else {
1113
+ deferred.settle_with(&channel, move |mut cx| {
1114
+ // TODO: throw error
1115
+ Ok(cx.undefined())
1116
+ });
1117
+ panic!("Failed to connect to runtime service.");
1118
+ };
1119
+ });
1120
+ Ok(promise)
1121
+ }
1122
+
1123
+ fn vector_memory_node(mut cx: FunctionContext) -> JsResult<JsPromise> {
1124
+ let channel = cx.channel();
1125
+ let (deferred, promise) = cx.promise();
1126
+ let self_ = cx.this()
1127
+ .downcast_or_throw::<JsBox<Chidori>, _>(&mut cx)?;
1128
+
1129
+ let arg0 = cx.argument::<JsValue>(0)?;
1130
+ let arg0_value: VectorMemoryNodeCreateOpts = match neon_serde3::from_value(&mut cx, arg0) {
1131
+ Ok(value) => value,
1132
+ Err(e) => {
1133
+ return cx.throw_error(e.to_string());
1134
+ }
1135
+ };
1136
+
1137
+ let queries: Vec<Option<String>> = if let Some(queries) = arg0_value.queries {
1138
+ queries.into_iter().map(|q| {
1139
+ if q == "None".to_string() {
1140
+ None
1141
+ } else {
1142
+ Some(q)
1143
+ }
1144
+ }).collect()
1145
+ } else {
1146
+ vec![]
1147
+ };
1148
+
1149
+ let file_id = self_.file_id.clone();
1150
+ let url = self_.url.clone();
1151
+ let branch = self_.current_branch;
1152
+ let rt = runtime(&mut cx)?;
1153
+ rt.spawn(async move {
1154
+ let node = create_vector_memory_node(
1155
+ arg0_value.name,
1156
+ queries,
1157
+ arg0_value.output.unwrap_or("type O {}".to_string()),
1158
+ arg0_value.action.unwrap_or("READ".to_string()),
1159
+ arg0_value.embedding_model.unwrap_or("TEXT_EMBEDDING_ADA_002".to_string()),
1160
+ arg0_value.template.unwrap_or("".to_string()),
1161
+ arg0_value.db_vendor.unwrap_or("QDRANT".to_string()),
1162
+ arg0_value.collection_name,
1163
+ arg0_value.output_tables.unwrap_or(vec![])
1164
+ );
1165
+ let node = if let Ok(node) = node {
1166
+ node
1167
+ } else {
1168
+ deferred.settle_with(&channel, move |mut cx| {
1169
+ // TODO: throw error
1170
+ Ok(cx.undefined())
1171
+ });
1172
+ panic!("Failed to connect to runtime service.");
1173
+ };
1174
+
1175
+ if let Ok(result ) = push_file_merge(&url, &file_id, node).await {
1176
+ deferred.settle_with(&channel, move |mut cx| {
1177
+ Ok(cx.boxed(RefCell::new(result)))
1178
+ });
1179
+ } else {
1180
+ deferred.settle_with(&channel, move |mut cx| {
1181
+ // TODO: throw error
1182
+ Ok(cx.undefined())
1183
+ });
1184
+ panic!("Failed to connect to runtime service.");
1185
+ };
1186
+ });
1187
+ Ok(promise)
1188
+ }
1189
+ //
1190
+ //
1191
+ // //
1192
+ // // fn observation_node(mut self_: PyRefMut<'_, Self>, name: String, query_def: Option<String>, template: String, model: String) -> PyResult<()> {
1193
+ // // let file_id = self_.file_id.clone();
1194
+ // // let node = create_observation_node(
1195
+ // // "".to_string(),
1196
+ // // None,
1197
+ // // "".to_string(),
1198
+ // // );
1199
+ // // executor::block_on(self_.client.merge(RequestFileMerge {
1200
+ // // id: file_id,
1201
+ // // file: Some(File {
1202
+ // // nodes: vec![node],
1203
+ // // ..Default::default()
1204
+ // // }),
1205
+ // // branch: 0,
1206
+ // // }));
1207
+ // // Ok(())
1208
+ // // }
1209
+ }
1210
+
1211
+
1212
+ fn neon_simple_fun(mut cx: FunctionContext) -> JsResult<JsString> {
1213
+ let port = cx.argument::<JsString>(0)?.value(&mut cx);
1214
+ Ok(cx.string(port))
1215
+ }
1216
+
1217
+ #[neon::main]
1218
+ fn main(mut cx: ModuleContext) -> NeonResult<()> {
1219
+ env_logger::init();
1220
+ cx.export_function("nodehandleDebugExample", NodeHandle::js_debug_example)?;
1221
+ cx.export_function("nodehandleRunWhen", NodeHandle::run_when)?;
1222
+ cx.export_function("nodehandleQuery", NodeHandle::query)?;
1223
+ cx.export_function("chidoriNew", Chidori::js_new)?;
1224
+ cx.export_function("chidoriStartServer", Chidori::start_server)?;
1225
+ cx.export_function("chidoriPlay", Chidori::play)?;
1226
+ cx.export_function("chidoriPause", Chidori::pause)?;
1227
+ cx.export_function("chidoriBranch", Chidori::branch)?;
1228
+ cx.export_function("chidoriQuery", Chidori::query)?;
1229
+ cx.export_function("chidoriGraphStructure", Chidori::display_graph_structure)?;
1230
+ cx.export_function("chidoriObjInterface", Chidori::obj_interface)?;
1231
+ cx.export_function("chidoriCustomNode", Chidori::custom_node)?;
1232
+ cx.export_function("chidoriDenoCodeNode", Chidori::deno_code_node)?;
1233
+ cx.export_function("chidoriVectorMemoryNode", Chidori::vector_memory_node)?;
1234
+ cx.export_function("chidoriPollLocalCodeNodeExecution", Chidori::poll_local_code_node_execution)?;
1235
+ cx.export_function("chidoriAckLocalCodeNodeExecution", Chidori::ack_local_code_node_execution)?;
1236
+ cx.export_function("chidoriRespondLocalCodeNodeExecution", Chidori::respond_local_code_node_execution)?;
1237
+ cx.export_function("simpleFun", neon_simple_fun)?;
1238
+ Ok(())
1239
+ }