use crate::Result;
use crate::agent::{Agent, AgentRef};
use crate::dir_context::{DirContext, join_support_pack_ref};
use crate::script::LuaEngine;
use std::sync::Arc;
#[derive(Debug, Default, Clone)]
pub struct Literals {
store: Arc<Vec<(&'static str, String)>>,
}
impl Literals {
pub(super) fn from_dir_context_and_agent_path(dir_context: &DirContext, agent: &Agent) -> Result<Literals> {
let mut store = Vec::new();
let agent_path = dir_context.current_dir().join(agent.file_path());
let agent_dir = agent_path
.parent()
.ok_or_else(|| format!("Agent {agent_path} does not have a parent dir"))?;
let aipack_paths = dir_context.aipack_paths();
store.push(("PWD", dir_context.current_dir().to_string()));
store.push(("AIPACK_VERSION", crate::VERSION.to_string()));
if let AgentRef::PackRef(pack_ref) = agent.agent_ref() {
store.push(("PACK_NAMESPACE", pack_ref.namespace().to_string()));
store.push(("PACK_NAME", pack_ref.name().to_string()));
if let Some(sub_path) = pack_ref.sub_path.as_deref() {
store.push(("PACK_SUB_PATH", sub_path.to_string()));
}
store.push(("PACK_REF", pack_ref.to_string()));
store.push(("PACK_IDENTITY", pack_ref.identity().to_string()));
store.push(("PACK_DIR", pack_ref.pack_dir.to_string()));
let identity_path = &pack_ref.identity().identity_as_path();
if let Some(aipack_wks_dir) = dir_context.aipack_paths().aipack_wks_dir() {
let path = join_support_pack_ref(aipack_wks_dir.path(), identity_path).to_string();
store.push(("PACK_WORKSPACE_SUPPORT_DIR", path.to_string()));
}
let pack_support_base = join_support_pack_ref(aipack_paths.aipack_base_dir().path(), identity_path);
store.push(("PACK_BASE_SUPPORT_DIR", pack_support_base.to_string()));
}
if let Some(wks_dir) = dir_context.wks_dir() {
store.push(("WORKSPACE_DIR", wks_dir.to_string()));
}
if let Some(aipack_wks_dir) = aipack_paths.aipack_wks_dir() {
store.push(("WORKSPACE_AIPACK_DIR", aipack_wks_dir.to_string()));
}
store.push(("BASE_AIPACK_DIR", aipack_paths.aipack_base_dir().to_string()));
store.push(("AGENT_NAME", agent.name().to_string()));
store.push(("AGENT_FILE_NAME", agent_path.name().to_string()));
store.push(("AGENT_FILE_PATH", agent_path.as_str().to_string()));
store.push(("AGENT_FILE_DIR", agent_dir.to_string()));
store.push(("AGENT_FILE_STEM", agent_path.stem().to_string()));
Ok(Self { store: Arc::new(store) })
}
}
impl Literals {
#[allow(unused)]
pub fn as_strs(&self) -> Vec<(&str, &str)> {
self.store.iter().map(|(p, v)| (*p, v.as_str())).collect()
}
}
impl Literals {
pub fn to_lua(&self, lua_engine: &LuaEngine) -> Result<mlua::Value> {
let table = lua_engine.create_table()?;
for (name, value) in self.as_strs() {
table.set(name, value)?;
}
Ok(mlua::Value::Table(table))
}
}
#[cfg(test)]
mod tests {
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
use crate::_test_support::{assert_ends_with, run_reflective_agent};
use value_ext::JsonValueExt;
#[tokio::test]
async fn test_run_literals_aipack_dir() -> Result<()> {
let script = r#"
return {
WORKSPACE_DIR = CTX.WORKSPACE_DIR,
WORKSPACE_AIPACK_DIR = CTX.WORKSPACE_AIPACK_DIR,
BASE_AIPACK_DIR = CTX.BASE_AIPACK_DIR,
AGENT_FILE_NAME = CTX.AGENT_FILE_NAME,
AGENT_FILE_PATH = CTX.AGENT_FILE_PATH,
AGENT_FILE_DIR = CTX.AGENT_FILE_DIR,
AGENT_FILE_STEM = CTX.AGENT_FILE_STEM,
-- those should be absent in the json, because nul in this case
PACK_BASE_SUPPORT_DIR = CTX.PACK_BASE_SUPPORT_DIR,
PACK_WORKSPACE_SUPPORT_DIR = CTX.PACK_WORKSPACE_SUPPORT_DIR,
}
"#;
let res = run_reflective_agent(script, None).await?;
assert_ends_with(res.x_get_str("WORKSPACE_DIR")?, "tests-data/sandbox-01");
assert_eq!(res.x_get_str("AGENT_FILE_NAME")?, "mock-reflective-agent.aip");
assert_eq!(res.x_get_str("AGENT_FILE_STEM")?, "mock-reflective-agent");
assert_ends_with(res.x_get_str("WORKSPACE_AIPACK_DIR")?, "tests-data/sandbox-01/.aipack");
assert_ends_with(res.x_get_str("BASE_AIPACK_DIR")?, "tests-data/.aipack-base");
assert_ends_with(res.x_get_str("AGENT_FILE_PATH")?, "mock-reflective-agent.aip");
Ok(())
}
}