Skip to content

Commit a0855d3

Browse files
committed
refactor: add metadata attr to remaining rust block asts
This also adds initial scaffolding for timing, and adds a ModelBlock and ArrayBlockBuilder. Signed-off-by: Nick Mitchell <[email protected]>
1 parent ef27624 commit a0855d3

File tree

5 files changed

+135
-103
lines changed

5 files changed

+135
-103
lines changed

pdl-live-react/src-tauri/src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use urlencoding::encode;
55

66
use crate::compile;
77
use crate::gui::new_window;
8-
use crate::pdl::interpreter::{load_scope, run_file_sync, RunOptions};
8+
use crate::pdl::interpreter::{RunOptions, load_scope, run_file_sync};
99

1010
#[cfg(desktop)]
1111
pub fn setup(app: &mut tauri::App) -> Result<bool, Box<dyn ::std::error::Error>> {

pdl-live-react/src-tauri/src/compile/beeai.rs

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ use ::std::path::{Path, PathBuf};
88
use duct::cmd;
99
use futures::executor::block_on;
1010
use serde::Deserialize;
11-
use serde_json::{from_reader, json, to_string, Map, Value};
11+
use serde_json::{Map, Value, from_reader, json, to_string};
1212
use tempfile::Builder;
1313

1414
use crate::pdl::ast::{
15-
ArrayBlock, CallBlock, EvalsTo, FunctionBlock, ListOrString, MessageBlock, MetadataBuilder,
16-
ModelBlock, ObjectBlock, PdlBaseType, PdlBlock, PdlOptionalType, PdlParser, PdlType,
17-
PythonCodeBlock, RepeatBlock, Role, TextBlock, TextBlockBuilder,
15+
ArrayBlockBuilder, CallBlock, EvalsTo, FunctionBlock, ListOrString, MessageBlock,
16+
MetadataBuilder, ModelBlockBuilder, ObjectBlock, PdlBaseType, PdlBlock, PdlOptionalType,
17+
PdlParser, PdlType, PythonCodeBlock, RepeatBlock, Role, TextBlock, TextBlockBuilder,
1818
};
1919
use crate::pdl::pip::pip_install_if_needed;
2020
use crate::pdl::requirements::BEEAI_FRAMEWORK;
@@ -200,32 +200,39 @@ fn call_tools(model: &String, parameters: &HashMap<String, Value>) -> PdlBlock {
200200
role: None,
201201
parser: None,
202202
text: vec![PdlBlock::Model(
203-
ModelBlock::new(model.as_str())
204-
.parameters(&strip_nulls(parameters))
205-
.input(PdlBlock::Array(ArrayBlock {
206-
array: vec![PdlBlock::Message(MessageBlock {
207-
metadata: None,
208-
role: Role::Tool,
209-
defsite: None,
210-
name: Some("${ tool.function.name }".to_string()),
211-
tool_call_id: Some("${ tool.id }".to_string()),
212-
content: Box::new(PdlBlock::Call(CallBlock {
213-
metadata: Some(
214-
MetadataBuilder::default()
215-
.defs(json_loads(
216-
&"args",
217-
&"pdl__args",
218-
&"${ tool.function.arguments }",
219-
))
220-
.build()
221-
.unwrap(),
222-
),
223-
call: EvalsTo::Jinja("${ pdl__tools[tool.function.name] }".to_string()), // look up tool in tool_declarations def (see below)
224-
args: Some("${ args }".into()), // invoke with arguments as specified by the model
225-
})),
226-
})],
227-
}))
228-
.build(),
203+
ModelBlockBuilder::default()
204+
.model(model.as_str())
205+
.parameters(strip_nulls(parameters))
206+
.input(PdlBlock::Array(
207+
ArrayBlockBuilder::default()
208+
.array(vec![PdlBlock::Message(MessageBlock {
209+
metadata: None,
210+
role: Role::Tool,
211+
defsite: None,
212+
name: Some("${ tool.function.name }".to_string()),
213+
tool_call_id: Some("${ tool.id }".to_string()),
214+
content: Box::new(PdlBlock::Call(CallBlock {
215+
metadata: Some(
216+
MetadataBuilder::default()
217+
.defs(json_loads(
218+
&"args",
219+
&"pdl__args",
220+
&"${ tool.function.arguments }",
221+
))
222+
.build()
223+
.unwrap(),
224+
),
225+
call: EvalsTo::Jinja(
226+
"${ pdl__tools[tool.function.name] }".to_string(),
227+
), // look up tool in tool_declarations def (see below)
228+
args: Some("${ args }".into()), // invoke with arguments as specified by the model
229+
})),
230+
})])
231+
.build()
232+
.unwrap(),
233+
))
234+
.build()
235+
.unwrap(),
229236
)],
230237
});
231238

@@ -237,6 +244,7 @@ fn call_tools(model: &String, parameters: &HashMap<String, Value>) -> PdlBlock {
237244

238245
// response.choices[0].message.tool_calls
239246
PdlBlock::Repeat(RepeatBlock {
247+
metadata: None,
240248
for_: for_,
241249
repeat: Box::new(repeat),
242250
})
@@ -416,6 +424,7 @@ pub fn compile(source_file_path: &str, debug: bool) -> Result<PdlBlock, Box<dyn
416424
function: schema,
417425
return_: Box::new(PdlBlock::PythonCode(PythonCodeBlock {
418426
// tool function definition
427+
metadata: None,
419428
lang: "python".to_string(),
420429
code: format!(
421430
"
@@ -489,28 +498,27 @@ asyncio.run(invoke())
489498
}));
490499
}
491500

492-
let model_response = if let Some(tools) = &tools {
493-
match tools.len() {
494-
0 => None,
495-
_ => Some("response".to_string()),
496-
}
497-
} else {
498-
None
499-
};
500-
501-
model_call.push(PdlBlock::Model(ModelBlock {
502-
metadata: Some(
501+
let mut model_builder = ModelBlockBuilder::default();
502+
model_builder
503+
.metadata(
503504
MetadataBuilder::default()
504505
.description(description)
505506
.build()
506507
.unwrap(),
507-
),
508-
input: None,
509-
model: model.clone(),
510-
model_response: model_response,
511-
pdl_usage: None,
512-
parameters: Some(with_tools(&tools, &parameters.state.dict)),
513-
}));
508+
)
509+
.model(model.clone())
510+
.parameters(with_tools(&tools, &parameters.state.dict));
511+
512+
if let Some(tools) = &tools {
513+
if tools.len() > 0 {
514+
// then we want the model response as a
515+
// "response" variable, so we can scan for
516+
// tool calls
517+
model_builder.model_response("response".to_string());
518+
}
519+
}
520+
521+
model_call.push(PdlBlock::Model(model_builder.build().unwrap()));
514522

515523
if let Some(tools) = tools {
516524
if tools.len() > 0 {

pdl-live-react/src-tauri/src/pdl/ast.rs

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use ::std::collections::HashMap;
2+
use ::std::time::{SystemTime, SystemTimeError};
3+
24
use indexmap::IndexMap;
35
use serde::{Deserialize, Serialize};
4-
use serde_json::{to_string, Number, Value};
6+
use serde_json::{Number, Value, to_string};
57

68
#[derive(Serialize, Deserialize, Debug, Clone)]
79
//why doesn't this work? #[serde(rename_all_fields(serialize = "lowercase"))]
@@ -52,10 +54,10 @@ pub enum PdlType {
5254
}
5355

5456
/// Timing information
55-
#[derive(Serialize, Deserialize, Debug, Clone)]
57+
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
5658
pub struct Timing {
57-
start_nanos: u64,
58-
end_nanos: u64,
59+
start_nanos: u128,
60+
end_nanos: u128,
5961
timezone: String,
6062
}
6163

@@ -86,6 +88,23 @@ pub struct Metadata {
8688
pub pdl_timing: Option<Timing>,
8789
}
8890

91+
impl Metadata {
92+
fn start(&mut self) -> Result<(), SystemTimeError> {
93+
let nanos = ::std::time::SystemTime::now()
94+
.duration_since(SystemTime::UNIX_EPOCH)?
95+
.as_nanos();
96+
if let Some(t) = &mut self.pdl_timing {
97+
t.start_nanos = nanos;
98+
} else {
99+
let mut t = Timing::default();
100+
t.start_nanos = nanos;
101+
self.pdl_timing = Some(t)
102+
}
103+
104+
Ok(())
105+
}
106+
}
107+
89108
/// Call a function
90109
#[derive(Serialize, Deserialize, Debug, Clone)]
91110
#[serde(tag = "kind", rename = "call")]
@@ -128,17 +147,17 @@ pub trait SequencingBlock {
128147
#[derive(Serialize, Deserialize, Debug, Clone)]
129148
#[serde(tag = "kind", rename = "lastOf")]
130149
pub struct LastOfBlock {
150+
#[serde(flatten)]
151+
#[serde(skip_serializing_if = "Option::is_none")]
152+
pub metadata: Option<Metadata>,
153+
131154
/// Sequence of blocks to execute
132155
#[serde(rename = "lastOf")]
133156
pub last_of: Vec<PdlBlock>,
134157

135158
#[serde(skip_serializing_if = "Option::is_none")]
136159
pub role: Option<Role>,
137160

138-
#[serde(flatten)]
139-
#[serde(skip_serializing_if = "Option::is_none")]
140-
pub metadata: Option<Metadata>,
141-
142161
#[serde(skip_serializing_if = "Option::is_none")]
143162
pub parser: Option<PdlParser>,
144163
}
@@ -260,8 +279,9 @@ pub struct PdlUsage {
260279
pub prompt_nanos: u64,
261280
}
262281

263-
#[derive(Serialize, Deserialize, Debug, Clone)]
282+
#[derive(Serialize, Deserialize, Debug, Clone, Default, derive_builder::Builder)]
264283
#[serde(tag = "kind", rename = "model")]
284+
#[builder(setter(into, strip_option), default)]
265285
pub struct ModelBlock {
266286
#[serde(flatten)]
267287
#[serde(skip_serializing_if = "Option::is_none")]
@@ -281,17 +301,6 @@ pub struct ModelBlock {
281301
}
282302

283303
impl ModelBlock {
284-
pub fn new(model: &str) -> Self {
285-
ModelBlock {
286-
metadata: Default::default(),
287-
model_response: None,
288-
parameters: None,
289-
pdl_usage: None,
290-
model: model.into(),
291-
input: None,
292-
}
293-
}
294-
295304
pub fn with_result(&self, result: PdlResult) -> Self {
296305
let mut c = self.clone();
297306
let mut metadata = if let Some(meta) = c.metadata {
@@ -307,25 +316,6 @@ impl ModelBlock {
307316
pub fn description(&self) -> Option<String> {
308317
self.metadata.as_ref().and_then(|m| m.description.clone())
309318
}
310-
311-
pub fn input(&mut self, input: PdlBlock) -> &mut Self {
312-
self.input = Some(Box::new(input));
313-
self
314-
}
315-
316-
pub fn input_str(&mut self, input: &str) -> &mut Self {
317-
self.input = Some(Box::new(PdlBlock::String(input.into())));
318-
self
319-
}
320-
321-
pub fn parameters(&mut self, parameters: &HashMap<String, Value>) -> &mut Self {
322-
self.parameters = Some(parameters.clone());
323-
self
324-
}
325-
326-
pub fn build(&self) -> Self {
327-
self.clone()
328-
}
329319
}
330320

331321
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -348,6 +338,10 @@ pub enum ListOrString {
348338
#[derive(Serialize, Deserialize, Debug, Clone)]
349339
#[serde(tag = "kind", rename = "repeat")]
350340
pub struct RepeatBlock {
341+
#[serde(flatten)]
342+
#[serde(skip_serializing_if = "Option::is_none")]
343+
pub metadata: Option<Metadata>,
344+
351345
/// Arrays to iterate over
352346
#[serde(rename = "for")]
353347
pub for_: HashMap<String, ListOrString>,
@@ -444,7 +438,14 @@ pub struct DataBlock {
444438
#[derive(Serialize, Deserialize, Debug, Clone)]
445439
#[serde(tag = "kind", rename = "code")]
446440
pub struct PythonCodeBlock {
441+
#[serde(flatten)]
442+
#[serde(skip_serializing_if = "Option::is_none")]
443+
pub metadata: Option<Metadata>,
444+
445+
/// Programming language of the code
447446
pub lang: String,
447+
448+
/// Code to execute
448449
pub code: String,
449450
}
450451

@@ -526,6 +527,10 @@ pub enum EvalsTo<S, T> {
526527
#[derive(Serialize, Deserialize, Debug, Clone)]
527528
#[serde(tag = "kind", rename = "if")]
528529
pub struct IfBlock {
530+
#[serde(flatten)]
531+
#[serde(skip_serializing_if = "Option::is_none")]
532+
pub metadata: Option<Metadata>,
533+
529534
/// The condition to check
530535
#[serde(rename = "if")]
531536
pub condition: EvalsTo<StringOrBoolean, bool>,
@@ -537,16 +542,17 @@ pub struct IfBlock {
537542
#[serde(rename = "else")]
538543
#[serde(skip_serializing_if = "Option::is_none")]
539544
pub else_: Option<Box<PdlBlock>>,
540-
541-
#[serde(flatten)]
542-
#[serde(skip_serializing_if = "Option::is_none")]
543-
pub metadata: Option<Metadata>,
544545
}
545546

546547
/// Return the array of values computed by each block of the list of blocks
547-
#[derive(Serialize, Deserialize, Debug, Clone)]
548+
#[derive(Serialize, Deserialize, Debug, Clone, Default, derive_builder::Builder)]
548549
#[serde(tag = "kind", rename = "array")]
550+
#[builder(setter(into, strip_option), default)]
549551
pub struct ArrayBlock {
552+
#[serde(flatten)]
553+
#[serde(skip_serializing_if = "Option::is_none")]
554+
pub metadata: Option<Metadata>,
555+
550556
/// Elements of the array
551557
pub array: Vec<PdlBlock>,
552558
}
@@ -555,6 +561,10 @@ pub struct ArrayBlock {
555561
#[derive(Serialize, Deserialize, Debug, Clone)]
556562
#[serde(tag = "kind", rename = "include")]
557563
pub struct IncludeBlock {
564+
#[serde(flatten)]
565+
#[serde(skip_serializing_if = "Option::is_none")]
566+
pub metadata: Option<Metadata>,
567+
558568
/// Name of the file to include.
559569
pub include: String,
560570
}
@@ -563,6 +573,10 @@ pub struct IncludeBlock {
563573
#[derive(Serialize, Deserialize, Debug, Clone)]
564574
#[serde(tag = "kind", rename = "import")]
565575
pub struct ImportBlock {
576+
#[serde(flatten)]
577+
#[serde(skip_serializing_if = "Option::is_none")]
578+
pub metadata: Option<Metadata>,
579+
566580
/// Name of the file to include.
567581
pub import: String,
568582
}
@@ -581,6 +595,9 @@ pub enum PdlBlock {
581595
Bool(bool),
582596
Number(Number),
583597
String(String),
598+
Function(FunctionBlock),
599+
600+
// the rest have Metadata; TODO refactor to make this more explicit
584601
If(IfBlock),
585602
Import(ImportBlock),
586603
Include(IncludeBlock),
@@ -590,7 +607,6 @@ pub enum PdlBlock {
590607
Array(ArrayBlock),
591608
Message(MessageBlock),
592609
Repeat(RepeatBlock),
593-
Function(FunctionBlock),
594610
PythonCode(PythonCodeBlock),
595611
Read(ReadBlock),
596612
Model(ModelBlock),

0 commit comments

Comments
 (0)