use std::collections::BTreeSet;
use std::io::Write;
use std::path::Path;
use aion_package::{ActivityDescriptor, CanonicalJson};
use anyhow::{Context, Result, bail};
use serde_json::json;
use crate::harness::HarnessKind;
use crate::worker_surface::{self, ServingSource};
const AGENT_SOURCE: ServingSource = ServingSource {
subject: "the agent worker",
serves: "serves",
omits: "does not serve",
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct AdvertisedSurface {
pub(crate) task_queue: String,
pub(crate) descriptors: Vec<ActivityDescriptor>,
}
impl AdvertisedSurface {
pub(crate) fn names(&self) -> BTreeSet<String> {
self.descriptors
.iter()
.map(|descriptor| descriptor.name.clone())
.collect()
}
}
pub(crate) fn derive(document: &Path, requested_queue: Option<&str>) -> Result<AdvertisedSurface> {
let contract = worker_surface::compile_contract(document)?;
let worker =
worker_surface::select_worker(document, &contract, requested_queue, "--task-queue")?;
let served = worker_surface::serviceable_action_names(worker);
if served.is_empty() {
let queue = &worker.task_queue;
if worker.actions.is_empty() {
bail!(
"queue `{queue}` in {} declares no actions, so an agent worker on it would \
advertise nothing and every queue carrying a deployed contract would refuse it",
document.display()
);
}
let bodied = worker
.actions
.iter()
.map(|action| action.name.as_str())
.collect::<Vec<_>>()
.join(", ");
bail!(
"every action on queue `{queue}` in {} carries a declared body ({bodied}), which the \
server runs itself; there is nothing on this queue for an agent worker to serve",
document.display()
);
}
let descriptors = worker_surface::reconcile(document, worker, &served, AGENT_SOURCE)?;
Ok(AdvertisedSurface {
task_queue: worker.task_queue.clone(),
descriptors: descriptors.into_values().collect(),
})
}
pub(crate) fn print(
writer: &mut impl Write,
surface: &AdvertisedSurface,
harness: Option<HarnessKind>,
) -> Result<()> {
let report = json!({
"task_queue": surface.task_queue,
"harness": harness.map(HarnessKind::name),
"intervention_capabilities": crate::harness::registration_capabilities(harness),
"actions": surface
.descriptors
.iter()
.map(|descriptor| {
json!({
"name": descriptor.name,
"input_schema": descriptor.input_schema,
"output_schema": descriptor.output_schema,
})
})
.collect::<Vec<_>>(),
});
serde_json::to_writer_pretty(&mut *writer, &CanonicalJson::new(report))
.context("failed to encode the advertised action surface")?;
writeln!(writer).context("failed to write the advertised action surface")?;
Ok(())
}