use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::ops::Range;
pub type Span = Range<usize>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Spanned<T> {
pub node: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub fn new(node: T, span: Span) -> Self {
Self { node, span }
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> {
Spanned {
node: f(self.node),
span: self.span,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct AgentFile {
pub config: Option<Spanned<ConfigBlock>>,
pub variables: Option<Spanned<VariablesBlock>>,
pub system: Option<Spanned<SystemBlock>>,
pub connections: Vec<Spanned<ConnectionBlock>>,
pub knowledge: Option<Spanned<KnowledgeBlock>>,
pub language: Option<Spanned<LanguageBlock>>,
pub start_agent: Option<Spanned<StartAgentBlock>>,
pub topics: Vec<Spanned<TopicBlock>>,
}
impl AgentFile {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConfigBlock {
pub agent_name: Spanned<String>,
pub agent_label: Option<Spanned<String>>,
pub description: Option<Spanned<String>>,
pub agent_type: Option<Spanned<String>>,
pub default_agent_user: Option<Spanned<String>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct VariablesBlock {
pub variables: Vec<Spanned<VariableDecl>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct VariableDecl {
pub name: Spanned<String>,
pub kind: VariableKind,
pub ty: Spanned<Type>,
pub default: Option<Spanned<Expr>>,
pub description: Option<Spanned<String>>,
pub source: Option<Spanned<Reference>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum VariableKind {
Mutable,
Linked,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Type {
String,
Number,
Boolean,
Object,
Date,
Timestamp,
Currency,
Id,
Datetime,
Time,
Integer,
Long,
List(Box<Type>),
}
impl Type {
pub fn parse_type(s: &str) -> Option<Self> {
match s {
"string" => Some(Type::String),
"number" => Some(Type::Number),
"boolean" => Some(Type::Boolean),
"object" => Some(Type::Object),
"date" => Some(Type::Date),
"timestamp" => Some(Type::Timestamp),
"currency" => Some(Type::Currency),
"id" => Some(Type::Id),
"datetime" => Some(Type::Datetime),
"time" => Some(Type::Time),
"integer" => Some(Type::Integer),
"long" => Some(Type::Long),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SystemBlock {
pub messages: Option<Spanned<SystemMessages>>,
pub instructions: Option<Spanned<Instructions>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SystemMessages {
pub welcome: Option<Spanned<String>>,
pub error: Option<Spanned<String>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConnectionBlock {
pub name: Spanned<String>,
pub entries: Vec<Spanned<ConnectionEntry>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ConnectionEntry {
pub name: Spanned<String>,
pub value: Spanned<String>,
}
pub type ConnectionsBlock = ConnectionBlock;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct KnowledgeBlock {
pub entries: Vec<Spanned<KnowledgeEntry>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct KnowledgeEntry {
pub name: Spanned<String>,
pub value: Spanned<Expr>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LanguageBlock {
pub entries: Vec<Spanned<LanguageEntry>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LanguageEntry {
pub name: Spanned<String>,
pub value: Spanned<Expr>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StartAgentBlock {
pub name: Spanned<String>,
pub description: Option<Spanned<String>>,
pub system: Option<Spanned<TopicSystemOverride>>,
pub actions: Option<Spanned<ActionsBlock>>,
pub before_reasoning: Option<Spanned<DirectiveBlock>>,
pub reasoning: Option<Spanned<ReasoningBlock>>,
pub after_reasoning: Option<Spanned<DirectiveBlock>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TopicBlock {
pub name: Spanned<String>,
pub description: Option<Spanned<String>>,
pub system: Option<Spanned<TopicSystemOverride>>,
pub actions: Option<Spanned<ActionsBlock>>,
pub before_reasoning: Option<Spanned<DirectiveBlock>>,
pub reasoning: Option<Spanned<ReasoningBlock>>,
pub after_reasoning: Option<Spanned<DirectiveBlock>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TopicSystemOverride {
pub instructions: Option<Spanned<Instructions>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActionsBlock {
pub actions: Vec<Spanned<ActionDef>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActionDef {
pub name: Spanned<String>,
pub description: Option<Spanned<String>>,
pub label: Option<Spanned<String>>,
pub require_user_confirmation: Option<Spanned<bool>>,
pub include_in_progress_indicator: Option<Spanned<bool>>,
pub progress_indicator_message: Option<Spanned<String>>,
pub inputs: Option<Spanned<Vec<Spanned<ParamDef>>>>,
pub outputs: Option<Spanned<Vec<Spanned<ParamDef>>>>,
pub target: Option<Spanned<String>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ParamDef {
pub name: Spanned<String>,
pub ty: Spanned<Type>,
pub description: Option<Spanned<String>>,
pub label: Option<Spanned<String>>,
pub is_required: Option<Spanned<bool>>,
pub filter_from_agent: Option<Spanned<bool>>,
pub is_displayable: Option<Spanned<bool>>,
pub complex_data_type_name: Option<Spanned<String>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct DirectiveBlock {
pub statements: Vec<Spanned<Stmt>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Stmt {
Set {
target: Spanned<Reference>,
value: Spanned<Expr>,
},
Run {
action: Spanned<Reference>,
with_clauses: Vec<Spanned<WithClause>>,
set_clauses: Vec<Spanned<SetClause>>,
},
If {
condition: Spanned<Expr>,
then_block: Vec<Spanned<Stmt>>,
else_block: Option<Vec<Spanned<Stmt>>>,
},
Transition { target: Spanned<Reference> },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WithClause {
pub param: Spanned<String>,
pub value: Spanned<WithValue>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum WithValue {
Expr(Expr),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct SetClause {
pub target: Spanned<Reference>,
pub source: Spanned<Expr>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OutputRef {
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReasoningBlock {
pub instructions: Option<Spanned<Instructions>>,
pub actions: Option<Spanned<Vec<Spanned<ReasoningAction>>>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReasoningAction {
pub name: Spanned<String>,
pub target: Spanned<ReasoningActionTarget>,
pub description: Option<Spanned<String>>,
pub available_when: Option<Spanned<Expr>>,
pub with_clauses: Vec<Spanned<WithClause>>,
pub set_clauses: Vec<Spanned<SetClause>>,
pub run_clauses: Vec<Spanned<RunClause>>,
pub if_clauses: Vec<Spanned<IfClause>>,
pub transition: Option<Spanned<Reference>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ReasoningActionTarget {
Action(Reference),
TransitionTo(Reference),
Escalate,
SetVariables,
TopicDelegate(Reference),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunClause {
pub action: Spanned<Reference>,
pub with_clauses: Vec<Spanned<WithClause>>,
pub set_clauses: Vec<Spanned<SetClause>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct IfClause {
pub condition: Spanned<Expr>,
pub transition: Option<Spanned<Reference>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Instructions {
Simple(String),
Static(Vec<Spanned<String>>),
Dynamic(Vec<Spanned<InstructionPart>>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum InstructionPart {
Text(String),
Interpolation(Expr),
Conditional {
condition: Spanned<Expr>,
then_parts: Vec<Spanned<InstructionPart>>,
else_parts: Option<Vec<Spanned<InstructionPart>>>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Expr {
Reference(Reference),
String(String),
Number(f64),
Bool(bool),
None,
SlotFill,
List(Vec<Spanned<Expr>>),
Object(IndexMap<String, Spanned<Expr>>),
BinOp {
left: Box<Spanned<Expr>>,
op: BinOp,
right: Box<Spanned<Expr>>,
},
UnaryOp {
op: UnaryOp,
operand: Box<Spanned<Expr>>,
},
Ternary {
condition: Box<Spanned<Expr>>,
then_expr: Box<Spanned<Expr>>,
else_expr: Box<Spanned<Expr>>,
},
Property {
object: Box<Spanned<Expr>>,
field: Spanned<String>,
},
Index {
object: Box<Spanned<Expr>>,
index: Box<Spanned<Expr>>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Reference {
pub namespace: String,
pub path: Vec<String>,
}
impl Reference {
pub fn new(namespace: impl Into<String>, path: Vec<String>) -> Self {
Self {
namespace: namespace.into(),
path,
}
}
pub fn full_path(&self) -> String {
if self.path.is_empty() {
format!("@{}", self.namespace)
} else {
format!("@{}.{}", self.namespace, self.path.join("."))
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinOp {
Eq, Ne, Lt, Gt, Le, Ge, Is, IsNot,
And, Or,
Add, Sub, }
impl BinOp {
pub fn precedence(&self) -> u8 {
match self {
BinOp::Or => 1,
BinOp::And => 2,
BinOp::Is | BinOp::IsNot => 3,
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge => 4,
BinOp::Add | BinOp::Sub => 5,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnaryOp {
Not, Neg, }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Comment {
pub text: String,
pub span: Span,
}