@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.
- package/Cargo.toml +77 -0
- package/build.rs +7 -0
- package/package.json +39 -0
- package/package_node/index.d.ts +0 -0
- package/package_node/index.js +96 -0
- package/package_python/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- package/package_python/.idea/misc.xml +4 -0
- package/package_python/.idea/modules.xml +8 -0
- package/package_python/.idea/package_python.iml +8 -0
- package/package_python/.idea/vcs.xml +6 -0
- package/package_python/__init__.py +0 -0
- package/package_python/__pycache__/__init__.cpython-310.pyc +0 -0
- package/package_python/__pycache__/test_chidori.cpython-310-pytest-7.4.0.pyc +0 -0
- package/package_python/__pycache__/test_promptgraph.cpython-310-pytest-7.4.0.pyc +0 -0
- package/package_python/chidori.pyi +30 -0
- package/package_python/py.typed +0 -0
- package/package_python/test_chidori.py +33 -0
- package/pyproject.toml +33 -0
- package/src/lib.rs +22 -0
- package/src/translations/mod.rs +8 -0
- package/src/translations/nodejs.rs +1239 -0
- package/src/translations/python.rs +964 -0
- package/src/translations/rust.rs +177 -0
- package/src/translations/wasm.rs +1 -0
- package/tests/nodejs/chidori.test.js +54 -0
- package/tests/nodejs/nodeHandle.test.js +17 -0
|
@@ -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
|
+
}
|