use std::fmt;
use std::sync::Arc;
use super::AgentSession;
use crate::capability::{
CapabilityDescriptor, CapabilityId, CapabilityKind, CapabilityValue, CodeCatalogGeneration,
ScopeCloseReport, SessionCapabilityRun, Sha256Digest, UiBinding, UiDocument,
UseCapabilityGeneration,
};
use crate::error::Result;
#[must_use = "a projected UI handle must remain alive for the complete host render window"]
pub struct ProjectedUiHandle {
descriptor: CapabilityDescriptor,
binding: Arc<UiBinding>,
capability_run: SessionCapabilityRun,
}
impl ProjectedUiHandle {
pub fn capability_id(&self) -> &CapabilityId {
self.descriptor.id()
}
pub fn public_name(&self) -> &str {
self.binding.public_name()
}
pub fn title(&self) -> &str {
self.binding.title()
}
pub fn description(&self) -> &str {
self.binding.description()
}
pub fn icon(&self) -> &str {
self.binding.icon()
}
pub fn order(&self) -> i32 {
self.binding.order()
}
pub fn document(&self) -> &UiDocument {
self.binding.document()
}
pub fn surface_digest(&self) -> &Sha256Digest {
self.binding.surface_digest()
}
pub fn dependencies(&self) -> &[CapabilityId] {
self.descriptor.dependencies()
}
pub fn catalog_generation(&self) -> CodeCatalogGeneration {
self.capability_run.projection().set().generation()
}
pub fn use_generation(&self) -> Option<&UseCapabilityGeneration> {
self.capability_run.run_scope().use_generation()
}
pub fn is_cancelled(&self) -> bool {
self.capability_run
.run_scope()
.cancellation()
.is_cancelled()
}
pub async fn close(self) -> Result<ScopeCloseReport> {
self.capability_run.close().await.map_err(Into::into)
}
}
impl fmt::Debug for ProjectedUiHandle {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("ProjectedUiHandle")
.field("capability_id", &self.capability_id())
.field("public_name", &self.public_name())
.field("catalog_generation", &self.catalog_generation())
.field("use_generation", &self.use_generation())
.field("surface_digest", &self.surface_digest())
.finish_non_exhaustive()
}
}
impl AgentSession {
pub async fn projected_ui(&self, public_name: &str) -> Result<Option<ProjectedUiHandle>> {
let Some(admitted) = self
.admit_projected_host_capability(CapabilityKind::Ui, public_name, |value| match value {
CapabilityValue::Ui(binding) => Some(Arc::clone(binding)),
_ => None,
})
.await?
else {
return Ok(None);
};
Ok(Some(ProjectedUiHandle {
descriptor: admitted.descriptor,
binding: admitted.value,
capability_run: admitted.capability_run,
}))
}
}